(function(global){
var define, requireModule, require, requirejs;
(function() {
var _isArray;
if (!Array.isArray) {
_isArray = function (x) {
return Object.prototype.toString.call(x) === "[object Array]";
};
} else {
_isArray = Array.isArray;
}
var registry = {}, seen = {}, state = {};
var FAILED = false;
define = function(name, deps, callback) {
if (!_isArray(deps)) {
callback = deps;
deps = [];
}
registry[name] = {
deps: deps,
callback: callback
};
};
function reify(deps, name, seen) {
var length = deps.length;
var reified = new Array(length);
var dep;
var exports;
for (var i = 0, l = length; i < l; i++) {
dep = deps[i];
if (dep === 'exports') {
exports = reified[i] = seen;
} else {
reified[i] = require(resolve(dep, name));
}
}
return {
deps: reified,
exports: exports
};
}
requirejs = require = requireModule = function(name) {
if (state[name] !== FAILED &&
seen.hasOwnProperty(name)) {
return seen[name];
}
if (!registry[name]) {
throw new Error('Could not find module ' + name);
}
var mod = registry[name];
var reified;
var module;
var loaded = false;
seen[name] = { }; // placeholder for run-time cycles
try {
reified = reify(mod.deps, name, seen[name]);
module = mod.callback.apply(this, reified.deps);
loaded = true;
} finally {
if (!loaded) {
state[name] = FAILED;
}
}
return reified.exports ? seen[name] : (seen[name] = module);
};
function resolve(child, name) {
if (child.charAt(0) !== '.') { return child; }
var parts = child.split('/');
var nameParts = name.split('/');
var parentBase;
if (nameParts.length === 1) {
parentBase = nameParts;
} else {
parentBase = nameParts.slice(0, -1);
}
for (var i = 0, l = parts.length; i < l; i++) {
var part = parts[i];
if (part === '..') { parentBase.pop(); }
else if (part === '.') { continue; }
else { parentBase.push(part); }
}
return parentBase.join('/');
}
requirejs.entries = requirejs._eak_seen = registry;
requirejs.clear = function(){
requirejs.entries = requirejs._eak_seen = registry = {};
seen = state = {};
};
})();
define("activemodel-adapter",
["activemodel-adapter/system","exports"],
function(__dependency1__, __exports__) {
"use strict";
var ActiveModelAdapter = __dependency1__.ActiveModelAdapter;
var ActiveModelSerializer = __dependency1__.ActiveModelSerializer;
__exports__.ActiveModelAdapter = ActiveModelAdapter;
__exports__.ActiveModelSerializer = ActiveModelSerializer;
});
define("activemodel-adapter/setup-container",
["ember-data/system/container_proxy","activemodel-adapter/system/active_model_serializer","activemodel-adapter/system/active_model_adapter","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
"use strict";
var ContainerProxy = __dependency1__["default"];
var ActiveModelSerializer = __dependency2__["default"];
var ActiveModelAdapter = __dependency3__["default"];
__exports__["default"] = function setupActiveModelAdapter(container, application){
var proxy = new ContainerProxy(container);
proxy.registerDeprecations([
{ deprecated: 'serializer:_ams', valid: 'serializer:-active-model' },
{ deprecated: 'adapter:_ams', valid: 'adapter:-active-model' }
]);
container.register('serializer:-active-model', ActiveModelSerializer);
container.register('adapter:-active-model', ActiveModelAdapter);
};
});
define("activemodel-adapter/system",
["activemodel-adapter/system/active_model_adapter","activemodel-adapter/system/active_model_serializer","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
var ActiveModelAdapter = __dependency1__["default"];
var ActiveModelSerializer = __dependency2__["default"];
__exports__.ActiveModelAdapter = ActiveModelAdapter;
__exports__.ActiveModelSerializer = ActiveModelSerializer;
});
define("activemodel-adapter/system/active_model_adapter",
["ember-data/adapters","ember-data/system/adapter","ember-inflector","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __exports__) {
"use strict";
var RESTAdapter = __dependency1__.RESTAdapter;
var InvalidError = __dependency2__.InvalidError;
var pluralize = __dependency3__.pluralize;
/**
@module ember-data
*/
var forEach = Ember.EnumerableUtils.forEach;
var decamelize = Ember.String.decamelize,
underscore = Ember.String.underscore;
/**
The ActiveModelAdapter is a subclass of the RESTAdapter designed to integrate
with a JSON API that uses an underscored naming convention instead of camelCasing.
It has been designed to work out of the box with the
[active_model_serializers](http://github.com/rails-api/active_model_serializers)
Ruby gem. This Adapter expects specific settings using ActiveModel::Serializers,
`embed :ids, include: true` which sideloads the records.
This adapter extends the DS.RESTAdapter by making consistent use of the camelization,
decamelization and pluralization methods to normalize the serialized JSON into a
format that is compatible with a conventional Rails backend and Ember Data.
## JSON Structure
The ActiveModelAdapter expects the JSON returned from your server to follow
the REST adapter conventions substituting underscored keys for camelcased ones.
Unlike the DS.RESTAdapter, async relationship keys must be the singular form
of the relationship name, followed by "_id" for DS.belongsTo relationships,
or "_ids" for DS.hasMany relationships.
### Conventional Names
Attribute names in your JSON payload should be the underscored versions of
the attributes in your Ember.js models.
For example, if you have a `Person` model:
```js
App.FamousPerson = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
occupation: DS.attr('string')
});
```
The JSON returned should look like this:
```js
{
"famous_person": {
"id": 1,
"first_name": "Barack",
"last_name": "Obama",
"occupation": "President"
}
}
```
Let's imagine that `Occupation` is just another model:
```js
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
occupation: DS.belongsTo('occupation')
});
App.Occupation = DS.Model.extend({
name: DS.attr('string'),
salary: DS.attr('number'),
people: DS.hasMany('person')
});
```
The JSON needed to avoid extra server calls, should look like this:
```js
{
"people": [{
"id": 1,
"first_name": "Barack",
"last_name": "Obama",
"occupation_id": 1
}],
"occupations": [{
"id": 1,
"name": "President",
"salary": 100000,
"person_ids": [1]
}]
}
```
@class ActiveModelAdapter
@constructor
@namespace DS
@extends DS.RESTAdapter
**/
var ActiveModelAdapter = RESTAdapter.extend({
defaultSerializer: '-active-model',
/**
The ActiveModelAdapter overrides the `pathForType` method to build
underscored URLs by decamelizing and pluralizing the object type name.
```js
this.pathForType("famousPerson");
//=> "famous_people"
```
@method pathForType
@param {String} type
@return String
*/
pathForType: function(type) {
var decamelized = decamelize(type);
var underscored = underscore(decamelized);
return pluralize(underscored);
},
/**
The ActiveModelAdapter overrides the `ajaxError` method
to return a DS.InvalidError for all 422 Unprocessable Entity
responses.
A 422 HTTP response from the server generally implies that the request
was well formed but the API was unable to process it because the
content was not semantically correct or meaningful per the API.
For more information on 422 HTTP Error code see 11.2 WebDAV RFC 4918
https://tools.ietf.org/html/rfc4918#section-11.2
@method ajaxError
@param {Object} jqXHR
@return error
*/
ajaxError: function(jqXHR) {
var error = this._super(jqXHR);
if (jqXHR && jqXHR.status === 422) {
var response = Ember.$.parseJSON(jqXHR.responseText),
errors = {};
if (response.errors !== undefined) {
var jsonErrors = response.errors;
forEach(Ember.keys(jsonErrors), function(key) {
errors[Ember.String.camelize(key)] = jsonErrors[key];
});
}
return new InvalidError(errors);
} else {
return error;
}
}
});
__exports__["default"] = ActiveModelAdapter;
});
define("activemodel-adapter/system/active_model_serializer",
["ember-inflector","ember-data/serializers/rest_serializer","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
var singularize = __dependency1__.singularize;
var RESTSerializer = __dependency2__["default"];
/**
@module ember-data
*/
var get = Ember.get,
forEach = Ember.EnumerableUtils.forEach,
camelize = Ember.String.camelize,
capitalize = Ember.String.capitalize,
decamelize = Ember.String.decamelize,
underscore = Ember.String.underscore;
/**
The ActiveModelSerializer is a subclass of the RESTSerializer designed to integrate
with a JSON API that uses an underscored naming convention instead of camelCasing.
It has been designed to work out of the box with the
[active_model_serializers](http://github.com/rails-api/active_model_serializers)
Ruby gem. This Serializer expects specific settings using ActiveModel::Serializers,
`embed :ids, include: true` which sideloads the records.
This serializer extends the DS.RESTSerializer by making consistent
use of the camelization, decamelization and pluralization methods to
normalize the serialized JSON into a format that is compatible with
a conventional Rails backend and Ember Data.
## JSON Structure
The ActiveModelSerializer expects the JSON returned from your server
to follow the REST adapter conventions substituting underscored keys
for camelcased ones.
### Conventional Names
Attribute names in your JSON payload should be the underscored versions of
the attributes in your Ember.js models.
For example, if you have a `Person` model:
```js
App.FamousPerson = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
occupation: DS.attr('string')
});
```
The JSON returned should look like this:
```js
{
"famous_person": {
"id": 1,
"first_name": "Barack",
"last_name": "Obama",
"occupation": "President"
}
}
```
Let's imagine that `Occupation` is just another model:
```js
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
occupation: DS.belongsTo('occupation')
});
App.Occupation = DS.Model.extend({
name: DS.attr('string'),
salary: DS.attr('number'),
people: DS.hasMany('person')
});
```
The JSON needed to avoid extra server calls, should look like this:
```js
{
"people": [{
"id": 1,
"first_name": "Barack",
"last_name": "Obama",
"occupation_id": 1
}],
"occupations": [{
"id": 1,
"name": "President",
"salary": 100000,
"person_ids": [1]
}]
}
```
@class ActiveModelSerializer
@namespace DS
@extends DS.RESTSerializer
*/
var ActiveModelSerializer = RESTSerializer.extend({
// SERIALIZE
/**
Converts camelCased attributes to underscored when serializing.
@method keyForAttribute
@param {String} attribute
@return String
*/
keyForAttribute: function(attr) {
return decamelize(attr);
},
/**
Underscores relationship names and appends "_id" or "_ids" when serializing
relationship keys.
@method keyForRelationship
@param {String} key
@param {String} kind
@return String
*/
keyForRelationship: function(rawKey, kind) {
var key = decamelize(rawKey);
if (kind === "belongsTo") {
return key + "_id";
} else if (kind === "hasMany") {
return singularize(key) + "_ids";
} else {
return key;
}
},
/*
Does not serialize hasMany relationships by default.
*/
serializeHasMany: Ember.K,
/**
Underscores the JSON root keys when serializing.
@method serializeIntoHash
@param {Object} hash
@param {subclass of DS.Model} type
@param {DS.Model} record
@param {Object} options
*/
serializeIntoHash: function(data, type, record, options) {
var root = underscore(decamelize(type.typeKey));
data[root] = this.serialize(record, options);
},
/**
Serializes a polymorphic type as a fully capitalized model name.
@method serializePolymorphicType
@param {DS.Model} record
@param {Object} json
@param {Object} relationship
*/
serializePolymorphicType: function(record, json, relationship) {
var key = relationship.key;
var belongsTo = get(record, key);
var jsonKey = underscore(key + "_type");
if (Ember.isNone(belongsTo)) {
json[jsonKey] = null;
} else {
json[jsonKey] = capitalize(camelize(belongsTo.constructor.typeKey));
}
},
// EXTRACT
/**
Add extra step to `DS.RESTSerializer.normalize` so links are normalized.
If your payload looks like:
```js
{
"post": {
"id": 1,
"title": "Rails is omakase",
"links": { "flagged_comments": "api/comments/flagged" }
}
}
```
The normalized version would look like this
```js
{
"post": {
"id": 1,
"title": "Rails is omakase",
"links": { "flaggedComments": "api/comments/flagged" }
}
}
```
@method normalize
@param {subclass of DS.Model} type
@param {Object} hash
@param {String} prop
@return Object
*/
normalize: function(type, hash, prop) {
this.normalizeLinks(hash);
return this._super(type, hash, prop);
},
/**
Convert `snake_cased` links to `camelCase`
@method normalizeLinks
@param {Object} data
*/
normalizeLinks: function(data){
if (data.links) {
var links = data.links;
for (var link in links) {
var camelizedLink = camelize(link);
if (camelizedLink !== link) {
links[camelizedLink] = links[link];
delete links[link];
}
}
}
},
/**
Normalize the polymorphic type from the JSON.
Normalize:
```js
{
id: "1"
minion: { type: "evil_minion", id: "12"}
}
```
To:
```js
{
id: "1"
minion: { type: "evilMinion", id: "12"}
}
```
@method normalizeRelationships
@private
*/
normalizeRelationships: function(type, hash) {
if (this.keyForRelationship) {
type.eachRelationship(function(key, relationship) {
var payloadKey, payload;
if (relationship.options.polymorphic) {
payloadKey = this.keyForAttribute(key);
payload = hash[payloadKey];
if (payload && payload.type) {
payload.type = this.typeForRoot(payload.type);
} else if (payload && relationship.kind === "hasMany") {
var self = this;
forEach(payload, function(single) {
single.type = self.typeForRoot(single.type);
});
}
} else {
payloadKey = this.keyForRelationship(key, relationship.kind);
if (!hash.hasOwnProperty(payloadKey)) { return; }
payload = hash[payloadKey];
}
hash[key] = payload;
if (key !== payloadKey) {
delete hash[payloadKey];
}
}, this);
}
}
});
__exports__["default"] = ActiveModelSerializer;
});
define("ember-data",
["ember-data/core","ember-data/ext/date","ember-data/system/promise_proxies","ember-data/system/store","ember-data/system/model","ember-data/system/adapter","ember-data/system/debug","ember-data/system/record_arrays","ember-data/system/record_array_manager","ember-data/adapters","ember-data/serializers/json_serializer","ember-data/serializers/rest_serializer","ember-inflector","ember-data/serializers/embedded_records_mixin","activemodel-adapter","ember-data/transforms","ember-data/system/relationships","ember-data/ember-initializer","ember-data/setup-container","ember-data/system/container_proxy","ember-data/system/relationships/relationship","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __dependency11__, __dependency12__, __dependency13__, __dependency14__, __dependency15__, __dependency16__, __dependency17__, __dependency18__, __dependency19__, __dependency20__, __dependency21__, __exports__) {
"use strict";
/**
Ember Data
@module ember-data
@main ember-data
*/
// support RSVP 2.x via resolve, but prefer RSVP 3.x's Promise.cast
Ember.RSVP.Promise.cast = Ember.RSVP.Promise.cast || Ember.RSVP.resolve;
var DS = __dependency1__["default"];
var PromiseArray = __dependency3__.PromiseArray;
var PromiseObject = __dependency3__.PromiseObject;
var Store = __dependency4__.Store;
var Model = __dependency5__.Model;
var Errors = __dependency5__.Errors;
var RootState = __dependency5__.RootState;
var attr = __dependency5__.attr;
var InvalidError = __dependency6__.InvalidError;
var Adapter = __dependency6__.Adapter;
var DebugAdapter = __dependency7__["default"];
var RecordArray = __dependency8__.RecordArray;
var FilteredRecordArray = __dependency8__.FilteredRecordArray;
var AdapterPopulatedRecordArray = __dependency8__.AdapterPopulatedRecordArray;
var ManyArray = __dependency8__.ManyArray;
var RecordArrayManager = __dependency9__["default"];
var RESTAdapter = __dependency10__.RESTAdapter;
var FixtureAdapter = __dependency10__.FixtureAdapter;
var JSONSerializer = __dependency11__["default"];
var RESTSerializer = __dependency12__["default"];
var EmbeddedRecordsMixin = __dependency14__["default"];
var ActiveModelAdapter = __dependency15__.ActiveModelAdapter;
var ActiveModelSerializer = __dependency15__.ActiveModelSerializer;
var Transform = __dependency16__.Transform;
var DateTransform = __dependency16__.DateTransform;
var NumberTransform = __dependency16__.NumberTransform;
var StringTransform = __dependency16__.StringTransform;
var BooleanTransform = __dependency16__.BooleanTransform;
var hasMany = __dependency17__.hasMany;
var belongsTo = __dependency17__.belongsTo;
var setupContainer = __dependency19__["default"];
var ContainerProxy = __dependency20__["default"];
var Relationship = __dependency21__.Relationship;
DS.Store = Store;
DS.PromiseArray = PromiseArray;
DS.PromiseObject = PromiseObject;
DS.Model = Model;
DS.RootState = RootState;
DS.attr = attr;
DS.Errors = Errors;
DS.Adapter = Adapter;
DS.InvalidError = InvalidError;
DS.DebugAdapter = DebugAdapter;
DS.RecordArray = RecordArray;
DS.FilteredRecordArray = FilteredRecordArray;
DS.AdapterPopulatedRecordArray = AdapterPopulatedRecordArray;
DS.ManyArray = ManyArray;
DS.RecordArrayManager = RecordArrayManager;
DS.RESTAdapter = RESTAdapter;
DS.FixtureAdapter = FixtureAdapter;
DS.RESTSerializer = RESTSerializer;
DS.JSONSerializer = JSONSerializer;
DS.Transform = Transform;
DS.DateTransform = DateTransform;
DS.StringTransform = StringTransform;
DS.NumberTransform = NumberTransform;
DS.BooleanTransform = BooleanTransform;
DS.ActiveModelAdapter = ActiveModelAdapter;
DS.ActiveModelSerializer = ActiveModelSerializer;
DS.EmbeddedRecordsMixin = EmbeddedRecordsMixin;
DS.belongsTo = belongsTo;
DS.hasMany = hasMany;
DS.Relationship = Relationship;
DS.ContainerProxy = ContainerProxy;
DS._setupContainer = setupContainer;
Ember.lookup.DS = DS;
__exports__["default"] = DS;
});
define("ember-data/adapters",
["ember-data/adapters/fixture_adapter","ember-data/adapters/rest_adapter","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
/**
@module ember-data
*/
var FixtureAdapter = __dependency1__["default"];
var RESTAdapter = __dependency2__["default"];
__exports__.RESTAdapter = RESTAdapter;
__exports__.FixtureAdapter = FixtureAdapter;
});
define("ember-data/adapters/fixture_adapter",
["ember-data/system/adapter","exports"],
function(__dependency1__, __exports__) {
"use strict";
/**
@module ember-data
*/
var get = Ember.get;
var fmt = Ember.String.fmt;
var indexOf = Ember.EnumerableUtils.indexOf;
var counter = 0;
var Adapter = __dependency1__["default"];
/**
`DS.FixtureAdapter` is an adapter that loads records from memory.
It's primarily used for development and testing. You can also use
`DS.FixtureAdapter` while working on the API but is not ready to
integrate yet. It is a fully functioning adapter. All CRUD methods
are implemented. You can also implement query logic that a remote
system would do. It's possible to develop your entire application
with `DS.FixtureAdapter`.
For information on how to use the `FixtureAdapter` in your
application please see the [FixtureAdapter
guide](/guides/models/the-fixture-adapter/).
@class FixtureAdapter
@namespace DS
@extends DS.Adapter
*/
__exports__["default"] = Adapter.extend({
// by default, fixtures are already in normalized form
serializer: null,
/**
If `simulateRemoteResponse` is `true` the `FixtureAdapter` will
wait a number of milliseconds before resolving promises with the
fixture values. The wait time can be configured via the `latency`
property.
@property simulateRemoteResponse
@type {Boolean}
@default true
*/
simulateRemoteResponse: true,
/**
By default the `FixtureAdapter` will simulate a wait of the
`latency` milliseconds before resolving promises with the fixture
values. This behavior can be turned off via the
`simulateRemoteResponse` property.
@property latency
@type {Number}
@default 50
*/
latency: 50,
/**
Implement this method in order to provide data associated with a type
@method fixturesForType
@param {Subclass of DS.Model} type
@return {Array}
*/
fixturesForType: function(type) {
if (type.FIXTURES) {
var fixtures = Ember.A(type.FIXTURES);
return fixtures.map(function(fixture){
var fixtureIdType = typeof fixture.id;
if(fixtureIdType !== "number" && fixtureIdType !== "string"){
throw new Error(fmt('the id property must be defined as a number or string for fixture %@', [fixture]));
}
fixture.id = fixture.id + '';
return fixture;
});
}
return null;
},
/**
Implement this method in order to query fixtures data
@method queryFixtures
@param {Array} fixture
@param {Object} query
@param {Subclass of DS.Model} type
@return {Promise|Array}
*/
queryFixtures: function(fixtures, query, type) {
Ember.assert('Not implemented: You must override the DS.FixtureAdapter::queryFixtures method to support querying the fixture store.');
},
/**
@method updateFixtures
@param {Subclass of DS.Model} type
@param {Array} fixture
*/
updateFixtures: function(type, fixture) {
if(!type.FIXTURES) {
type.FIXTURES = [];
}
var fixtures = type.FIXTURES;
this.deleteLoadedFixture(type, fixture);
fixtures.push(fixture);
},
/**
Implement this method in order to provide json for CRUD methods
@method mockJSON
@param {Subclass of DS.Model} type
@param {DS.Model} record
*/
mockJSON: function(store, type, record) {
return store.serializerFor(type).serialize(record, { includeId: true });
},
/**
@method generateIdForRecord
@param {DS.Store} store
@param {DS.Model} record
@return {String} id
*/
generateIdForRecord: function(store) {
return "fixture-" + counter++;
},
/**
@method find
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {String} id
@return {Promise} promise
*/
find: function(store, type, id) {
var fixtures = this.fixturesForType(type);
var fixture;
Ember.assert("Unable to find fixtures for model type "+type.toString() +". If you're defining your fixtures using `Model.FIXTURES = ...`, please change it to `Model.reopenClass({ FIXTURES: ... })`.", fixtures);
if (fixtures) {
fixture = Ember.A(fixtures).findBy('id', id);
}
if (fixture) {
return this.simulateRemoteCall(function() {
return fixture;
}, this);
}
},
/**
@method findMany
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Array} ids
@return {Promise} promise
*/
findMany: function(store, type, ids) {
var fixtures = this.fixturesForType(type);
Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
if (fixtures) {
fixtures = fixtures.filter(function(item) {
return indexOf(ids, item.id) !== -1;
});
}
if (fixtures) {
return this.simulateRemoteCall(function() {
return fixtures;
}, this);
}
},
/**
@private
@method findAll
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {String} sinceToken
@return {Promise} promise
*/
findAll: function(store, type) {
var fixtures = this.fixturesForType(type);
Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures);
return this.simulateRemoteCall(function() {
return fixtures;
}, this);
},
/**
@private
@method findQuery
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} query
@param {DS.AdapterPopulatedRecordArray} recordArray
@return {Promise} promise
*/
findQuery: function(store, type, query, array) {
var fixtures = this.fixturesForType(type);
Ember.assert("Unable to find fixtures for model type " + type.toString(), fixtures);
fixtures = this.queryFixtures(fixtures, query, type);
if (fixtures) {
return this.simulateRemoteCall(function() {
return fixtures;
}, this);
}
},
/**
@method createRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {DS.Model} record
@return {Promise} promise
*/
createRecord: function(store, type, record) {
var fixture = this.mockJSON(store, type, record);
this.updateFixtures(type, fixture);
return this.simulateRemoteCall(function() {
return fixture;
}, this);
},
/**
@method updateRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {DS.Model} record
@return {Promise} promise
*/
updateRecord: function(store, type, record) {
var fixture = this.mockJSON(store, type, record);
this.updateFixtures(type, fixture);
return this.simulateRemoteCall(function() {
return fixture;
}, this);
},
/**
@method deleteRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {DS.Model} record
@return {Promise} promise
*/
deleteRecord: function(store, type, record) {
this.deleteLoadedFixture(type, record);
return this.simulateRemoteCall(function() {
// no payload in a deletion
return null;
});
},
/*
@method deleteLoadedFixture
@private
@param type
@param record
*/
deleteLoadedFixture: function(type, record) {
var existingFixture = this.findExistingFixture(type, record);
if (existingFixture) {
var index = indexOf(type.FIXTURES, existingFixture);
type.FIXTURES.splice(index, 1);
return true;
}
},
/*
@method findExistingFixture
@private
@param type
@param record
*/
findExistingFixture: function(type, record) {
var fixtures = this.fixturesForType(type);
var id = get(record, 'id');
return this.findFixtureById(fixtures, id);
},
/*
@method findFixtureById
@private
@param fixtures
@param id
*/
findFixtureById: function(fixtures, id) {
return Ember.A(fixtures).find(function(r) {
if (''+get(r, 'id') === ''+id) {
return true;
} else {
return false;
}
});
},
/*
@method simulateRemoteCall
@private
@param callback
@param context
*/
simulateRemoteCall: function(callback, context) {
var adapter = this;
return new Ember.RSVP.Promise(function(resolve) {
var value = Ember.copy(callback.call(context), true);
if (get(adapter, 'simulateRemoteResponse')) {
// Schedule with setTimeout
Ember.run.later(function() {
resolve(value);
}, get(adapter, 'latency'));
} else {
// Asynchronous, but at the of the runloop with zero latency
Ember.run.schedule('actions', null, function() {
resolve(value);
});
}
}, "DS: FixtureAdapter#simulateRemoteCall");
}
});
});
define("ember-data/adapters/rest_adapter",
["ember-data/system/adapter","ember-data/system/map","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
/**
@module ember-data
*/
var Adapter = __dependency1__.Adapter;
var InvalidError = __dependency1__.InvalidError;
var MapWithDefault = __dependency2__.MapWithDefault;
var get = Ember.get;
var forEach = Ember.ArrayPolyfills.forEach;
/**
The REST adapter allows your store to communicate with an HTTP server by
transmitting JSON via XHR. Most Ember.js apps that consume a JSON API
should use the REST adapter.
This adapter is designed around the idea that the JSON exchanged with
the server should be conventional.
## JSON Structure
The REST adapter expects the JSON returned from your server to follow
these conventions.
### Object Root
The JSON payload should be an object that contains the record inside a
root property. For example, in response to a `GET` request for
`/posts/1`, the JSON should look like this:
```js
{
"post": {
"id": 1,
"title": "I'm Running to Reform the W3C's Tag",
"author": "Yehuda Katz"
}
}
```
Similarly, in response to a `GET` request for `/posts`, the JSON should
look like this:
```js
{
"posts": [
{
"id": 1,
"title": "I'm Running to Reform the W3C's Tag",
"author": "Yehuda Katz"
},
{
"id": 2,
"title": "Rails is omakase",
"author": "D2H"
}
]
}
```
### Conventional Names
Attribute names in your JSON payload should be the camelCased versions of
the attributes in your Ember.js models.
For example, if you have a `Person` model:
```js
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
occupation: DS.attr('string')
});
```
The JSON returned should look like this:
```js
{
"person": {
"id": 5,
"firstName": "Barack",
"lastName": "Obama",
"occupation": "President"
}
}
```
## Customization
### Endpoint path customization
Endpoint paths can be prefixed with a `namespace` by setting the namespace
property on the adapter:
```js
DS.RESTAdapter.reopen({
namespace: 'api/1'
});
```
Requests for `App.Person` would now target `/api/1/people/1`.
### Host customization
An adapter can target other hosts by setting the `host` property.
```js
DS.RESTAdapter.reopen({
host: 'https://api.example.com'
});
```
### Headers customization
Some APIs require HTTP headers, e.g. to provide an API key. Arbitrary
headers can be set as key/value pairs on the `RESTAdapter`'s `headers`
object and Ember Data will send them along with each ajax request.
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
headers: {
"API_KEY": "secret key",
"ANOTHER_HEADER": "Some header value"
}
});
```
`headers` can also be used as a computed property to support dynamic
headers. In the example below, the `session` object has been
injected into an adapter by Ember's container.
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
headers: function() {
return {
"API_KEY": this.get("session.authToken"),
"ANOTHER_HEADER": "Some header value"
};
}.property("session.authToken")
});
```
In some cases, your dynamic headers may require data from some
object outside of Ember's observer system (for example
`document.cookie`). You can use the
[volatile](/api/classes/Ember.ComputedProperty.html#method_volatile)
function to set the property into a non-cached mode causing the headers to
be recomputed with every request.
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
headers: function() {
return {
"API_KEY": Ember.get(document.cookie.match(/apiKey\=([^;]*)/), "1"),
"ANOTHER_HEADER": "Some header value"
};
}.property().volatile()
});
```
@class RESTAdapter
@constructor
@namespace DS
@extends DS.Adapter
*/
__exports__["default"] = Adapter.extend({
defaultSerializer: '-rest',
/**
By default the RESTAdapter will send each find request coming from a `store.find`
or from accessing a relationship separately to the server. If your server supports passing
ids as a query string, you can set coalesceFindRequests to true to coalesce all find requests
within a single runloop.
For example, if you have an initial payload of
```javascript
post: {
id:1,
comments: [1,2]
}
```
By default calling `post.get('comments')` will trigger the following requests(assuming the
comments haven't been loaded before):
```
GET /comments/1
GET /comments/2
```
If you set coalesceFindRequests to `true` it will instead trigger the following request:
```
GET /comments?ids[]=1&ids[]=2
```
Setting coalesceFindRequests to `true` also works for `store.find` requests and `belongsTo`
relationships accessed within the same runloop. If you set `coalesceFindRequests: true`
```javascript
store.find('comment', 1);
store.find('comment', 2);
```
will also send a request to: `GET /comments?ids[]=1&ids[]=2`
Note: Requests coalescing rely on URL building strategy. So if you override `buildUrl` in your app
`groupRecordsForFindMany` more likely should be overriden as well in order for coalescing to work.
@property coalesceFindRequests
@type {boolean}
*/
coalesceFindRequests: false,
/**
Endpoint paths can be prefixed with a `namespace` by setting the namespace
property on the adapter:
```javascript
DS.RESTAdapter.reopen({
namespace: 'api/1'
});
```
Requests for `App.Post` would now target `/api/1/post/`.
@property namespace
@type {String}
*/
/**
An adapter can target other hosts by setting the `host` property.
```javascript
DS.RESTAdapter.reopen({
host: 'https://api.example.com'
});
```
Requests for `App.Post` would now target `https://api.example.com/post/`.
@property host
@type {String}
*/
/**
Some APIs require HTTP headers, e.g. to provide an API
key. Arbitrary headers can be set as key/value pairs on the
`RESTAdapter`'s `headers` object and Ember Data will send them
along with each ajax request. For dynamic headers see [headers
customization](/api/data/classes/DS.RESTAdapter.html#toc_headers-customization).
```javascript
App.ApplicationAdapter = DS.RESTAdapter.extend({
headers: {
"API_KEY": "secret key",
"ANOTHER_HEADER": "Some header value"
}
});
```
@property headers
@type {Object}
*/
/**
Called by the store in order to fetch the JSON for a given
type and ID.
The `find` method makes an Ajax request to a URL computed by `buildURL`, and returns a
promise for the resulting payload.
This method performs an HTTP `GET` request with the id provided as part of the query string.
@method find
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {String} id
@param {DS.Model} record
@return {Promise} promise
*/
find: function(store, type, id, record) {
return this.ajax(this.buildURL(type.typeKey, id, record), 'GET');
},
/**
Called by the store in order to fetch a JSON array for all
of the records for a given type.
The `findAll` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
promise for the resulting payload.
@private
@method findAll
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {String} sinceToken
@return {Promise} promise
*/
findAll: function(store, type, sinceToken) {
var query;
if (sinceToken) {
query = { since: sinceToken };
}
return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });
},
/**
Called by the store in order to fetch a JSON array for
the records that match a particular query.
The `findQuery` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
promise for the resulting payload.
The `query` argument is a simple JavaScript object that will be passed directly
to the server as parameters.
@private
@method findQuery
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} query
@return {Promise} promise
*/
findQuery: function(store, type, query) {
return this.ajax(this.buildURL(type.typeKey), 'GET', { data: query });
},
/**
Called by the store in order to fetch several records together if `coalesceFindRequests` is true
For example, if the original payload looks like:
```js
{
"id": 1,
"title": "Rails is omakase",
"comments": [ 1, 2, 3 ]
}
```
The IDs will be passed as a URL-encoded Array of IDs, in this form:
```
ids[]=1&ids[]=2&ids[]=3
```
Many servers, such as Rails and PHP, will automatically convert this URL-encoded array
into an Array for you on the server-side. If you want to encode the
IDs, differently, just override this (one-line) method.
The `findMany` method makes an Ajax (HTTP GET) request to a URL computed by `buildURL`, and returns a
promise for the resulting payload.
@method findMany
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Array} ids
@param {Array} records
@return {Promise} promise
*/
findMany: function(store, type, ids, records) {
return this.ajax(this.buildURL(type.typeKey, ids, records), 'GET', { data: { ids: ids } });
},
/**
Called by the store in order to fetch a JSON array for
the unloaded records in a has-many relationship that were originally
specified as a URL (inside of `links`).
For example, if your original payload looks like this:
```js
{
"post": {
"id": 1,
"title": "Rails is omakase",
"links": { "comments": "/posts/1/comments" }
}
}
```
This method will be called with the parent record and `/posts/1/comments`.
The `findHasMany` method will make an Ajax (HTTP GET) request to the originally specified URL.
If the URL is host-relative (starting with a single slash), the
request will use the host specified on the adapter (if any).
@method findHasMany
@param {DS.Store} store
@param {DS.Model} record
@param {String} url
@return {Promise} promise
*/
findHasMany: function(store, record, url, relationship) {
var host = get(this, 'host');
var id = get(record, 'id');
var type = record.constructor.typeKey;
if (host && url.charAt(0) === '/' && url.charAt(1) !== '/') {
url = host + url;
}
return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET');
},
/**
Called by the store in order to fetch a JSON array for
the unloaded records in a belongs-to relationship that were originally
specified as a URL (inside of `links`).
For example, if your original payload looks like this:
```js
{
"person": {
"id": 1,
"name": "Tom Dale",
"links": { "group": "/people/1/group" }
}
}
```
This method will be called with the parent record and `/people/1/group`.
The `findBelongsTo` method will make an Ajax (HTTP GET) request to the originally specified URL.
@method findBelongsTo
@param {DS.Store} store
@param {DS.Model} record
@param {String} url
@return {Promise} promise
*/
findBelongsTo: function(store, record, url, relationship) {
var id = get(record, 'id');
var type = record.constructor.typeKey;
return this.ajax(this.urlPrefix(url, this.buildURL(type, id)), 'GET');
},
/**
Called by the store when a newly created record is
saved via the `save` method on a model record instance.
The `createRecord` method serializes the record and makes an Ajax (HTTP POST) request
to a URL computed by `buildURL`.
See `serialize` for information on how to customize the serialized form
of a record.
@method createRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {DS.Model} record
@return {Promise} promise
*/
createRecord: function(store, type, record) {
var data = {};
var serializer = store.serializerFor(type.typeKey);
serializer.serializeIntoHash(data, type, record, { includeId: true });
return this.ajax(this.buildURL(type.typeKey, null, record), "POST", { data: data });
},
/**
Called by the store when an existing record is saved
via the `save` method on a model record instance.
The `updateRecord` method serializes the record and makes an Ajax (HTTP PUT) request
to a URL computed by `buildURL`.
See `serialize` for information on how to customize the serialized form
of a record.
@method updateRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {DS.Model} record
@return {Promise} promise
*/
updateRecord: function(store, type, record) {
var data = {};
var serializer = store.serializerFor(type.typeKey);
serializer.serializeIntoHash(data, type, record);
var id = get(record, 'id');
return this.ajax(this.buildURL(type.typeKey, id, record), "PUT", { data: data });
},
/**
Called by the store when a record is deleted.
The `deleteRecord` method makes an Ajax (HTTP DELETE) request to a URL computed by `buildURL`.
@method deleteRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {DS.Model} record
@return {Promise} promise
*/
deleteRecord: function(store, type, record) {
var id = get(record, 'id');
return this.ajax(this.buildURL(type.typeKey, id, record), "DELETE");
},
/**
Builds a URL for a given type and optional ID.
By default, it pluralizes the type's name (for example, 'post'
becomes 'posts' and 'person' becomes 'people'). To override the
pluralization see [pathForType](#method_pathForType).
If an ID is specified, it adds the ID to the path generated
for the type, separated by a `/`.
@method buildURL
@param {String} type
@param {String} id
@param {DS.Model} record
@return {String} url
*/
buildURL: function(type, id, record) {
var url = [],
host = get(this, 'host'),
prefix = this.urlPrefix();
if (type) { url.push(this.pathForType(type)); }
//We might get passed in an array of ids from findMany
//in which case we don't want to modify the url, as the
//ids will be passed in through a query param
if (id && !Ember.isArray(id)) { url.push(encodeURIComponent(id)); }
if (prefix) { url.unshift(prefix); }
url = url.join('/');
if (!host && url) { url = '/' + url; }
return url;
},
/**
@method urlPrefix
@private
@param {String} path
@param {String} parentUrl
@return {String} urlPrefix
*/
urlPrefix: function(path, parentURL) {
var host = get(this, 'host');
var namespace = get(this, 'namespace');
var url = [];
if (path) {
// Absolute path
if (path.charAt(0) === '/') {
if (host) {
path = path.slice(1);
url.push(host);
}
// Relative path
} else if (!/^http(s)?:\/\//.test(path)) {
url.push(parentURL);
}
} else {
if (host) { url.push(host); }
if (namespace) { url.push(namespace); }
}
if (path) {
url.push(path);
}
return url.join('/');
},
_stripIDFromURL: function(store, record) {
var type = store.modelFor(record);
var url = this.buildURL(type.typeKey, record.get('id'), record);
var expandedURL = url.split('/');
//Case when the url is of the format ...something/:id
var lastSegment = expandedURL[ expandedURL.length - 1 ];
var id = record.get('id');
if (lastSegment === id) {
expandedURL[expandedURL.length - 1] = "";
} else if(endsWith(lastSegment, '?id=' + id)) {
//Case when the url is of the format ...something?id=:id
expandedURL[expandedURL.length - 1] = lastSegment.substring(0, lastSegment.length - id.length - 1);
}
return expandedURL.join('/');
},
/**
Organize records into groups, each of which is to be passed to separate
calls to `findMany`.
This implementation groups together records that have the same base URL but
differing ids. For example `/comments/1` and `/comments/2` will be grouped together
because we know findMany can coalesce them together as `/comments?ids[]=1&ids[]=2`
It also supports urls where ids are passed as a query param, such as `/comments?id=1`
but not those where there is more than 1 query param such as `/comments?id=2&name=David`
Currently only the query param of `id` is supported. If you need to support others, please
override this or the `_stripIDFromURL` method.
It does not group records that have differing base urls, such as for example: `/posts/1/comments/2`
and `/posts/2/comments/3`
@method groupRecordsForFindMany
@param {Array} records
@return {Array} an array of arrays of records, each of which is to be
loaded separately by `findMany`.
*/
groupRecordsForFindMany: function (store, records) {
var groups = MapWithDefault.create({defaultValue: function(){return [];}});
var adapter = this;
forEach.call(records, function(record){
var baseUrl = adapter._stripIDFromURL(store, record);
groups.get(baseUrl).push(record);
});
function splitGroupToFitInUrl(group, maxUrlLength) {
var baseUrl = adapter._stripIDFromURL(store, group[0]);
var idsSize = 0;
var splitGroups = [[]];
forEach.call(group, function(record) {
var additionalLength = '&ids[]='.length + record.get('id.length');
if (baseUrl.length + idsSize + additionalLength >= maxUrlLength) {
idsSize = 0;
splitGroups.push([]);
}
idsSize += additionalLength;
var lastGroupIndex = splitGroups.length - 1;
splitGroups[lastGroupIndex].push(record);
});
return splitGroups;
}
var groupsArray = [];
groups.forEach(function(group, key){
// http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
var maxUrlLength = 2048;
var splitGroups = splitGroupToFitInUrl(group, maxUrlLength);
forEach.call(splitGroups, function(splitGroup) {
groupsArray.push(splitGroup);
});
});
return groupsArray;
},
/**
Determines the pathname for a given type.
By default, it pluralizes the type's name (for example,
'post' becomes 'posts' and 'person' becomes 'people').
### Pathname customization
For example if you have an object LineItem with an
endpoint of "/line_items/".
```js
App.ApplicationAdapter = DS.RESTAdapter.extend({
pathForType: function(type) {
var decamelized = Ember.String.decamelize(type);
return Ember.String.pluralize(decamelized);
}
});
```
@method pathForType
@param {String} type
@return {String} path
**/
pathForType: function(type) {
var camelized = Ember.String.camelize(type);
return Ember.String.pluralize(camelized);
},
/**
Takes an ajax response, and returns a relevant error.
Returning a `DS.InvalidError` from this method will cause the
record to transition into the `invalid` state and make the
`errors` object available on the record.
```javascript
App.ApplicationAdapter = DS.RESTAdapter.extend({
ajaxError: function(jqXHR) {
var error = this._super(jqXHR);
if (jqXHR && jqXHR.status === 422) {
var jsonErrors = Ember.$.parseJSON(jqXHR.responseText)["errors"];
return new DS.InvalidError(jsonErrors);
} else {
return error;
}
}
});
```
Note: As a correctness optimization, the default implementation of
the `ajaxError` method strips out the `then` method from jquery's
ajax response (jqXHR). This is important because the jqXHR's
`then` method fulfills the promise with itself resulting in a
circular "thenable" chain which may cause problems for some
promise libraries.
@method ajaxError
@param {Object} jqXHR
@param {Object} responseText
@return {Object} jqXHR
*/
ajaxError: function(jqXHR, responseText) {
if (jqXHR && typeof jqXHR === 'object') {
jqXHR.then = null;
}
return jqXHR;
},
/**
Takes an ajax response, and returns the json payload.
By default this hook just returns the jsonPayload passed to it.
You might want to override it in two cases:
1. Your API might return useful results in the request headers.
If you need to access these, you can override this hook to copy them
from jqXHR to the payload object so they can be processed in you serializer.
2. Your API might return errors as successful responses with status code
200 and an Errors text or object. You can return a DS.InvalidError from
this hook and it will automatically reject the promise and put your record
into the invald state.
@method ajaxError
@param {Object} jqXHR
@param {Object} jsonPayload
@return {Object} jqXHR
*/
ajaxSuccess: function(jqXHR, jsonPayload) {
return jsonPayload;
},
/**
Takes a URL, an HTTP method and a hash of data, and makes an
HTTP request.
When the server responds with a payload, Ember Data will call into `extractSingle`
or `extractArray` (depending on whether the original query was for one record or
many records).
By default, `ajax` method has the following behavior:
* It sets the response `dataType` to `"json"`
* If the HTTP method is not `"GET"`, it sets the `Content-Type` to be
`application/json; charset=utf-8`
* If the HTTP method is not `"GET"`, it stringifies the data passed in. The
data is the serialized record in the case of a save.
* Registers success and failure handlers.
@method ajax
@private
@param {String} url
@param {String} type The request type GET, POST, PUT, DELETE etc.
@param {Object} hash
@return {Promise} promise
*/
ajax: function(url, type, options) {
var adapter = this;
return new Ember.RSVP.Promise(function(resolve, reject) {
var hash = adapter.ajaxOptions(url, type, options);
hash.success = function(json, textStatus, jqXHR) {
json = adapter.ajaxSuccess(jqXHR, json);
if (json instanceof InvalidError) {
Ember.run(null, reject, json);
} else {
Ember.run(null, resolve, json);
}
};
hash.error = function(jqXHR, textStatus, errorThrown) {
Ember.run(null, reject, adapter.ajaxError(jqXHR, jqXHR.responseText));
};
Ember.$.ajax(hash);
}, "DS: RESTAdapter#ajax " + type + " to " + url);
},
/**
@method ajaxOptions
@private
@param {String} url
@param {String} type The request type GET, POST, PUT, DELETE etc.
@param {Object} hash
@return {Object} hash
*/
ajaxOptions: function(url, type, options) {
var hash = options || {};
hash.url = url;
hash.type = type;
hash.dataType = 'json';
hash.context = this;
if (hash.data && type !== 'GET') {
hash.contentType = 'application/json; charset=utf-8';
hash.data = JSON.stringify(hash.data);
}
var headers = get(this, 'headers');
if (headers !== undefined) {
hash.beforeSend = function (xhr) {
forEach.call(Ember.keys(headers), function(key) {
xhr.setRequestHeader(key, headers[key]);
});
};
}
return hash;
}
});
//From http://stackoverflow.com/questions/280634/endswith-in-javascript
function endsWith(string, suffix){
if (typeof String.prototype.endsWith !== 'function') {
return string.indexOf(suffix, string.length - suffix.length) !== -1;
} else {
return string.endsWith(suffix);
}
}
});
define("ember-data/core",
["exports"],
function(__exports__) {
"use strict";
/**
@module ember-data
*/
/**
All Ember Data methods and functions are defined inside of this namespace.
@class DS
@static
*/
var DS;
if ('undefined' === typeof DS) {
/**
@property VERSION
@type String
@default '1.0.0-beta.11'
@static
*/
DS = Ember.Namespace.create({
VERSION: '1.0.0-beta.11'
});
if (Ember.libraries) {
Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION);
}
}
__exports__["default"] = DS;
});
define("ember-data/ember-initializer",
["ember-data/setup-container"],
function(__dependency1__) {
"use strict";
var setupContainer = __dependency1__["default"];
var K = Ember.K;
/**
@module ember-data
*/
/*
This code initializes Ember-Data onto an Ember application.
If an Ember.js developer defines a subclass of DS.Store on their application,
as `App.ApplicationStore` (or via a module system that resolves to `store:application`)
this code will automatically instantiate it and make it available on the
router.
Additionally, after an application's controllers have been injected, they will
each have the store made available to them.
For example, imagine an Ember.js application with the following classes:
App.ApplicationStore = DS.Store.extend({
adapter: 'custom'
});
App.PostsController = Ember.ArrayController.extend({
// ...
});
When the application is initialized, `App.ApplicationStore` will automatically be
instantiated, and the instance of `App.PostsController` will have its `store`
property set to that instance.
Note that this code will only be run if the `ember-application` package is
loaded. If Ember Data is being used in an environment other than a
typical application (e.g., node.js where only `ember-runtime` is available),
this code will be ignored.
*/
Ember.onLoad('Ember.Application', function(Application) {
Application.initializer({
name: "ember-data",
initialize: setupContainer
});
// Deprecated initializers to satisfy old code that depended on them
Application.initializer({
name: "store",
after: "ember-data",
initialize: K
});
Application.initializer({
name: "activeModelAdapter",
before: "store",
initialize: K
});
Application.initializer({
name: "transforms",
before: "store",
initialize: K
});
Application.initializer({
name: "data-adapter",
before: "store",
initialize: K
});
Application.initializer({
name: "injectStore",
before: "store",
initialize: K
});
});
});
define("ember-data/ext/date",
[],
function() {
"use strict";
/**
@module ember-data
*/
/**
Date.parse with progressive enhancement for ISO 8601 <https://github.com/csnover/js-iso8601>
© 2011 Colin Snover <http://zetafleet.com>
Released under MIT license.
@class Date
@namespace Ember
@static
*/
Ember.Date = Ember.Date || {};
var origParse = Date.parse, numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
/**
@method parse
@param {Date} date
@return {Number} timestamp
*/
Ember.Date.parse = function (date) {
var timestamp, struct, minutesOffset = 0;
// ES5 §<IP_ADDRESS> states that the string should attempt to be parsed as a Date Time String Format string
// before falling back to any implementation-specific date parsing, so that’s what we do, even if native
// implementations could be faster
// 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm
if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
// avoid NaN timestamps caused by “undefined” values being passed to Date.UTC
for (var i = 0, k; (k = numericKeys[i]); ++i) {
struct[k] = +struct[k] || 0;
}
// allow undefined days and months
struct[2] = (+struct[2] || 1) - 1;
struct[3] = +struct[3] || 1;
if (struct[8] !== 'Z' && struct[9] !== undefined) {
minutesOffset = struct[10] * 60 + struct[11];
if (struct[9] === '+') {
minutesOffset = 0 - minutesOffset;
}
}
timestamp = Date.UTC(struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7]);
}
else {
timestamp = origParse ? origParse(date) : NaN;
}
return timestamp;
};
if (Ember.EXTEND_PROTOTYPES === true || Ember.EXTEND_PROTOTYPES.Date) {
Date.parse = Ember.Date.parse;
}
});
define("ember-data/initializers/data_adapter",
["ember-data/system/debug/debug_adapter","exports"],
function(__dependency1__, __exports__) {
"use strict";
var DebugAdapter = __dependency1__["default"];
/**
Configures a container with injections on Ember applications
for the Ember-Data store. Accepts an optional namespace argument.
@method initializeStoreInjections
@param {Ember.Container} container
*/
__exports__["default"] = function initializeDebugAdapter(container){
container.register('data-adapter:main', DebugAdapter);
};
});
define("ember-data/initializers/store",
["ember-data/serializers","ember-data/adapters","ember-data/system/container_proxy","ember-data/system/store","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __exports__) {
"use strict";
var JSONSerializer = __dependency1__.JSONSerializer;
var RESTSerializer = __dependency1__.RESTSerializer;
var RESTAdapter = __dependency2__.RESTAdapter;
var ContainerProxy = __dependency3__["default"];
var Store = __dependency4__["default"];
/**
Configures a container for use with an Ember-Data
store. Accepts an optional namespace argument.
@method initializeStore
@param {Ember.Container} container
@param {Object} [application] an application namespace
*/
__exports__["default"] = function initializeStore(container, application){
Ember.deprecate('Specifying a custom Store for Ember Data on your global namespace as `App.Store` ' +
'has been deprecated. Please use `App.ApplicationStore` instead.', !(application && application.Store));
container.register('store:main', container.lookupFactory('store:application') || (application && application.Store) || Store);
// allow older names to be looked up
var proxy = new ContainerProxy(container);
proxy.registerDeprecations([
{ deprecated: 'serializer:_default', valid: 'serializer:-default' },
{ deprecated: 'serializer:_rest', valid: 'serializer:-rest' },
{ deprecated: 'adapter:_rest', valid: 'adapter:-rest' }
]);
// new go forward paths
container.register('serializer:-default', JSONSerializer);
container.register('serializer:-rest', RESTSerializer);
container.register('adapter:-rest', RESTAdapter);
// Eagerly generate the store so defaultStore is populated.
// TODO: Do this in a finisher hook
container.lookup('store:main');
};
});
define("ember-data/initializers/store_injections",
["exports"],
function(__exports__) {
"use strict";
/**
Configures a container with injections on Ember applications
for the Ember-Data store. Accepts an optional namespace argument.
@method initializeStoreInjections
@param {Ember.Container} container
*/
__exports__["default"] = function initializeStoreInjections(container){
container.injection('controller', 'store', 'store:main');
container.injection('route', 'store', 'store:main');
container.injection('serializer', 'store', 'store:main');
container.injection('data-adapter', 'store', 'store:main');
};
});
define("ember-data/initializers/transforms",
["ember-data/transforms","exports"],
function(__dependency1__, __exports__) {
"use strict";
var BooleanTransform = __dependency1__.BooleanTransform;
var DateTransform = __dependency1__.DateTransform;
var StringTransform = __dependency1__.StringTransform;
var NumberTransform = __dependency1__.NumberTransform;
/**
Configures a container for use with Ember-Data
transforms.
@method initializeTransforms
@param {Ember.Container} container
*/
__exports__["default"] = function initializeTransforms(container){
container.register('transform:boolean', BooleanTransform);
container.register('transform:date', DateTransform);
container.register('transform:number', NumberTransform);
container.register('transform:string', StringTransform);
};
});
define("ember-data/serializers",
["ember-data/serializers/json_serializer","ember-data/serializers/rest_serializer","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
var JSONSerializer = __dependency1__["default"];
var RESTSerializer = __dependency2__["default"];
__exports__.JSONSerializer = JSONSerializer;
__exports__.RESTSerializer = RESTSerializer;
});
define("ember-data/serializers/embedded_records_mixin",
["exports"],
function(__exports__) {
"use strict";
var get = Ember.get;
var forEach = Ember.EnumerableUtils.forEach;
var camelize = Ember.String.camelize;
/**
## Using Embedded Records
`DS.EmbeddedRecordsMixin` supports serializing embedded records.
To set up embedded records, include the mixin when extending a serializer
then define and configure embedded (model) relationships.
Below is an example of a per-type serializer ('post' type).
```js
App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
author: { embedded: 'always' },
comments: { serialize: 'ids' }
}
});
```
Note that this use of `{ embedded: 'always' }` is unrelated to
the `{ embedded: 'always' }` that is defined as an option on `DS.attr` as part of
defining a model while working with the ActiveModelSerializer. Nevertheless,
using `{ embedded: 'always' }` as an option to DS.attr is not a valid way to setup
embedded records.
The `attrs` option for a resource `{ embedded: 'always' }` is shorthand for:
```js
{
serialize: 'records',
deserialize: 'records'
}
```
### Configuring Attrs
A resource's `attrs` option may be set to use `ids`, `records` or false for the
`serialize` and `deserialize` settings.
The `attrs` property can be set on the ApplicationSerializer or a per-type
serializer.
In the case where embedded JSON is expected while extracting a payload (reading)
the setting is `deserialize: 'records'`, there is no need to use `ids` when
extracting as that is the default behavior without this mixin if you are using
the vanilla EmbeddedRecordsMixin. Likewise, to embed JSON in the payload while
serializing `serialize: 'records'` is the setting to use. There is an option of
not embedding JSON in the serialized payload by using `serialize: 'ids'`. If you
do not want the relationship sent at all, you can use `serialize: false`.
### EmbeddedRecordsMixin defaults
If you do not overwrite `attrs` for a specific relationship, the `EmbeddedRecordsMixin`
will behave in the following way:
BelongsTo: `{ serialize: 'id', deserialize: 'id' }`
HasMany: `{ serialize: false, deserialize: 'ids' }`
### Model Relationships
Embedded records must have a model defined to be extracted and serialized. Note that
when defining any relationships on your model such as `belongsTo` and `hasMany`, you
should not both specify `async:true` and also indicate through the serializer's
`attrs` attribute that the related model should be embedded. If a model is
declared embedded, then do not use `async:true`.
To successfully extract and serialize embedded records the model relationships
must be setup correcty See the
[defining relationships](/guides/models/defining-models/#toc_defining-relationships)
section of the **Defining Models** guide page.
Records without an `id` property are not considered embedded records, model
instances must have an `id` property to be used with Ember Data.
### Example JSON payloads, Models and Serializers
**When customizing a serializer it is important to grok what the customizations
are. Please read the docs for the methods this mixin provides, in case you need
to modify it to fit your specific needs.**
For example review the docs for each method of this mixin:
* [normalize](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_normalize)
* [serializeBelongsTo](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeBelongsTo)
* [serializeHasMany](/api/data/classes/DS.EmbeddedRecordsMixin.html#method_serializeHasMany)
@class EmbeddedRecordsMixin
@namespace DS
*/
var EmbeddedRecordsMixin = Ember.Mixin.create({
/**
Normalize the record and recursively normalize/extract all the embedded records
while pushing them into the store as they are encountered
A payload with an attr configured for embedded records needs to be extracted:
```js
{
"post": {
"id": "1"
"title": "Rails is omakase",
"comments": [{
"id": "1",
"body": "Rails is unagi"
}, {
"id": "2",
"body": "Omakase O_o"
}]
}
}
```
@method normalize
@param {subclass of DS.Model} type
@param {Object} hash to be normalized
@param {String} key the hash has been referenced by
@return {Object} the normalized hash
**/
normalize: function(type, hash, prop) {
var normalizedHash = this._super(type, hash, prop);
return extractEmbeddedRecords(this, this.store, type, normalizedHash);
},
keyForRelationship: function(key, type){
if (this.hasDeserializeRecordsOption(key)) {
return this.keyForAttribute(key);
} else {
return this._super(key, type) || key;
}
},
/**
Serialize `belongsTo` relationship when it is configured as an embedded object.
This example of an author model belongs to a post model:
```js
Post = DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
author: DS.belongsTo('author')
});
Author = DS.Model.extend({
name: DS.attr('string'),
post: DS.belongsTo('post')
});
```
Use a custom (type) serializer for the post model to configure embedded author
```js
App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
author: {embedded: 'always'}
}
})
```
A payload with an attribute configured for embedded records can serialize
the records together under the root attribute's payload:
```js
{
"post": {
"id": "1"
"title": "Rails is omakase",
"author": {
"id": "2"
"name": "dhh"
}
}
}
```
@method serializeBelongsTo
@param {DS.Model} record
@param {Object} json
@param {Object} relationship
*/
serializeBelongsTo: function(record, json, relationship) {
var attr = relationship.key;
if (this.noSerializeOptionSpecified(attr)) {
this._super(record, json, relationship);
return;
}
var includeIds = this.hasSerializeIdsOption(attr);
var includeRecords = this.hasSerializeRecordsOption(attr);
var embeddedRecord = record.get(attr);
var key;
if (includeIds) {
key = this.keyForRelationship(attr, relationship.kind);
if (!embeddedRecord) {
json[key] = null;
} else {
json[key] = get(embeddedRecord, 'id');
}
} else if (includeRecords) {
key = this.keyForAttribute(attr);
if (!embeddedRecord) {
json[key] = null;
} else {
json[key] = embeddedRecord.serialize({includeId: true});
this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, json[key]);
}
}
},
/**
Serialize `hasMany` relationship when it is configured as embedded objects.
This example of a post model has many comments:
```js
Post = DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
comments: DS.hasMany('comment')
});
Comment = DS.Model.extend({
body: DS.attr('string'),
post: DS.belongsTo('post')
});
```
Use a custom (type) serializer for the post model to configure embedded comments
```js
App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
comments: {embedded: 'always'}
}
})
```
A payload with an attribute configured for embedded records can serialize
the records together under the root attribute's payload:
```js
{
"post": {
"id": "1"
"title": "Rails is omakase",
"body": "I want this for my ORM, I want that for my template language..."
"comments": [{
"id": "1",
"body": "Rails is unagi"
}, {
"id": "2",
"body": "Omakase O_o"
}]
}
}
```
The attrs options object can use more specific instruction for extracting and
serializing. When serializing, an option to embed `ids` or `records` can be set.
When extracting the only option is `records`.
So `{embedded: 'always'}` is shorthand for:
`{serialize: 'records', deserialize: 'records'}`
To embed the `ids` for a related object (using a hasMany relationship):
```js
App.PostSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
comments: {serialize: 'ids', deserialize: 'records'}
}
})
```
```js
{
"post": {
"id": "1"
"title": "Rails is omakase",
"body": "I want this for my ORM, I want that for my template language..."
"comments": ["1", "2"]
}
}
```
@method serializeHasMany
@param {DS.Model} record
@param {Object} json
@param {Object} relationship
*/
serializeHasMany: function(record, json, relationship) {
var attr = relationship.key;
if (this.noSerializeOptionSpecified(attr)) {
this._super(record, json, relationship);
return;
}
var includeIds = this.hasSerializeIdsOption(attr);
var includeRecords = this.hasSerializeRecordsOption(attr);
var key;
if (includeIds) {
key = this.keyForRelationship(attr, relationship.kind);
json[key] = get(record, attr).mapBy('id');
} else if (includeRecords) {
key = this.keyForAttribute(attr);
json[key] = get(record, attr).map(function(embeddedRecord) {
var serializedEmbeddedRecord = embeddedRecord.serialize({includeId: true});
this.removeEmbeddedForeignKey(record, embeddedRecord, relationship, serializedEmbeddedRecord);
return serializedEmbeddedRecord;
}, this);
}
},
/**
When serializing an embedded record, modify the property (in the json payload)
that refers to the parent record (foreign key for relationship).
Serializing a `belongsTo` relationship removes the property that refers to the
parent record
Serializing a `hasMany` relationship does not remove the property that refers to
the parent record.
@method removeEmbeddedForeignKey
@param {DS.Model} record
@param {DS.Model} embeddedRecord
@param {Object} relationship
@param {Object} json
*/
removeEmbeddedForeignKey: function (record, embeddedRecord, relationship, json) {
if (relationship.kind === 'hasMany') {
return;
} else if (relationship.kind === 'belongsTo') {
var parentRecord = record.constructor.inverseFor(relationship.key);
if (parentRecord) {
var name = parentRecord.name;
var embeddedSerializer = this.store.serializerFor(embeddedRecord.constructor);
var parentKey = embeddedSerializer.keyForRelationship(name, parentRecord.kind);
if (parentKey) {
delete json[parentKey];
}
}
}
},
// checks config for attrs option to embedded (always) - serialize and deserialize
hasEmbeddedAlwaysOption: function (attr) {
var option = this.attrsOption(attr);
return option && option.embedded === 'always';
},
// checks config for attrs option to serialize ids
hasSerializeRecordsOption: function(attr) {
var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr);
var option = this.attrsOption(attr);
return alwaysEmbed || (option && (option.serialize === 'records'));
},
// checks config for attrs option to serialize records
hasSerializeIdsOption: function(attr) {
var option = this.attrsOption(attr);
return option && (option.serialize === 'ids' || option.serialize === 'id');
},
// checks config for attrs option to serialize records
noSerializeOptionSpecified: function(attr) {
var option = this.attrsOption(attr);
return !(option && (option.serialize || option.embedded));
},
// checks config for attrs option to deserialize records
// a defined option object for a resource is treated the same as
// `deserialize: 'records'`
hasDeserializeRecordsOption: function(attr) {
var alwaysEmbed = this.hasEmbeddedAlwaysOption(attr);
var option = this.attrsOption(attr);
return alwaysEmbed || (option && option.deserialize === 'records');
},
attrsOption: function(attr) {
var attrs = this.get('attrs');
return attrs && (attrs[camelize(attr)] || attrs[attr]);
}
});
// chooses a relationship kind to branch which function is used to update payload
// does not change payload if attr is not embedded
function extractEmbeddedRecords(serializer, store, type, partial) {
type.eachRelationship(function(key, relationship) {
if (serializer.hasDeserializeRecordsOption(key)) {
var embeddedType = store.modelFor(relationship.type.typeKey);
if (relationship.kind === "hasMany") {
if (relationship.options.polymorphic) {
extractEmbeddedHasManyPolymorphic(store, key, partial);
}
else {
extractEmbeddedHasMany(store, key, embeddedType, partial);
}
}
if (relationship.kind === "belongsTo") {
extractEmbeddedBelongsTo(store, key, embeddedType, partial);
}
}
});
return partial;
}
// handles embedding for `hasMany` relationship
function extractEmbeddedHasMany(store, key, embeddedType, hash) {
if (!hash[key]) {
return hash;
}
var ids = [];
var embeddedSerializer = store.serializerFor(embeddedType.typeKey);
forEach(hash[key], function(data) {
var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null);
store.push(embeddedType, embeddedRecord);
ids.push(embeddedRecord.id);
});
hash[key] = ids;
return hash;
}
function extractEmbeddedHasManyPolymorphic(store, key, hash) {
if (!hash[key]) {
return hash;
}
var ids = [];
forEach(hash[key], function(data) {
var typeKey = data.type;
var embeddedSerializer = store.serializerFor(typeKey);
var embeddedType = store.modelFor(typeKey);
var primaryKey = get(embeddedSerializer, 'primaryKey');
var embeddedRecord = embeddedSerializer.normalize(embeddedType, data, null);
store.push(embeddedType, embeddedRecord);
ids.push({ id: embeddedRecord[primaryKey], type: typeKey });
});
hash[key] = ids;
return hash;
}
function extractEmbeddedBelongsTo(store, key, embeddedType, hash) {
if (!hash[key]) {
return hash;
}
var embeddedSerializer = store.serializerFor(embeddedType.typeKey);
var embeddedRecord = embeddedSerializer.normalize(embeddedType, hash[key], null);
store.push(embeddedType, embeddedRecord);
hash[key] = embeddedRecord.id;
//TODO Need to add a reference to the parent later so relationship works between both `belongsTo` records
return hash;
}
__exports__["default"] = EmbeddedRecordsMixin;
});
define("ember-data/serializers/json_serializer",
["exports"],
function(__exports__) {
"use strict";
var get = Ember.get;
var isNone = Ember.isNone;
var map = Ember.ArrayPolyfills.map;
var merge = Ember.merge;
/**
In Ember Data a Serializer is used to serialize and deserialize
records when they are transferred in and out of an external source.
This process involves normalizing property names, transforming
attribute values and serializing relationships.
For maximum performance Ember Data recommends you use the
[RESTSerializer](DS.RESTSerializer.html) or one of its subclasses.
`JSONSerializer` is useful for simpler or legacy backends that may
not support the http://jsonapi.org/ spec.
@class JSONSerializer
@namespace DS
*/
__exports__["default"] = Ember.Object.extend({
/**
The primaryKey is used when serializing and deserializing
data. Ember Data always uses the `id` property to store the id of
the record. The external source may not always follow this
convention. In these cases it is useful to override the
primaryKey property to match the primaryKey of your external
store.
Example
```javascript
App.ApplicationSerializer = DS.JSONSerializer.extend({
primaryKey: '_id'
});
```
@property primaryKey
@type {String}
@default 'id'
*/
primaryKey: 'id',
/**
The `attrs` object can be used to declare a simple mapping between
property names on `DS.Model` records and payload keys in the
serialized JSON object representing the record. An object with the
property `key` can also be used to designate the attribute's key on
the response payload.
Example
```javascript
App.Person = DS.Model.extend({
firstName: DS.attr('string'),
lastName: DS.attr('string'),
occupation: DS.attr('string'),
admin: DS.attr('boolean')
});
App.PersonSerializer = DS.JSONSerializer.extend({
attrs: {
admin: 'is_admin',
occupation: {key: 'career'}
}
});
```
You can also remove attributes by setting the `serialize` key to
false in your mapping object.
Example
```javascript
App.PersonSerializer = DS.JSONSerializer.extend({
attrs: {
admin: {serialize: false},
occupation: {key: 'career'}
}
});
```
When serialized:
```javascript
{
"career": "magician"
}
```
Note that the `admin` is now not included in the payload.
@property attrs
@type {Object}
*/
/**
Given a subclass of `DS.Model` and a JSON object this method will
iterate through each attribute of the `DS.Model` and invoke the
`DS.Transform#deserialize` method on the matching property of the
JSON object. This method is typically called after the
serializer's `normalize` method.
@method applyTransforms
@private
@param {subclass of DS.Model} type
@param {Object} data The data to transform
@return {Object} data The transformed data object
*/
applyTransforms: function(type, data) {
type.eachTransformedAttribute(function applyTransform(key, type) {
if (!data.hasOwnProperty(key)) { return; }
var transform = this.transformFor(type);
data[key] = transform.deserialize(data[key]);
}, this);
return data;
},
/**
Normalizes a part of the JSON payload returned by
the server. You should override this method, munge the hash
and call super if you have generic normalization to do.
It takes the type of the record that is being normalized
(as a DS.Model class), the property where the hash was
originally found, and the hash to normalize.
You can use this method, for example, to normalize underscored keys to camelized
or other general-purpose normalizations.
Example
```javascript
App.ApplicationSerializer = DS.JSONSerializer.extend({
normalize: function(type, hash) {
var fields = Ember.get(type, 'fields');
fields.forEach(function(field) {
var payloadField = Ember.String.underscore(field);
if (field === payloadField) { return; }
hash[field] = hash[payloadField];
delete hash[payloadField];
});
return this._super.apply(this, arguments);
}
});
```
@method normalize
@param {subclass of DS.Model} type
@param {Object} hash
@return {Object}
*/
normalize: function(type, hash) {
if (!hash) { return hash; }
this.normalizeId(hash);
this.normalizeAttributes(type, hash);
this.normalizeRelationships(type, hash);
this.normalizeUsingDeclaredMapping(type, hash);
this.applyTransforms(type, hash);
return hash;
},
/**
You can use this method to normalize all payloads, regardless of whether they
represent single records or an array.
For example, you might want to remove some extraneous data from the payload:
```js
App.ApplicationSerializer = DS.JSONSerializer.extend({
normalizePayload: function(payload) {
delete payload.version;
delete payload.status;
return payload;
}
});
```
@method normalizePayload
@param {Object} payload
@return {Object} the normalized payload
*/
normalizePayload: function(payload) {
return payload;
},
/**
@method normalizeAttributes
@private
*/
normalizeAttributes: function(type, hash) {
var payloadKey;
if (this.keyForAttribute) {
type.eachAttribute(function(key) {
payloadKey = this.keyForAttribute(key);
if (key === payloadKey) { return; }
if (!hash.hasOwnProperty(payloadKey)) { return; }
hash[key] = hash[payloadKey];
delete hash[payloadKey];
}, this);
}
},
/**
@method normalizeRelationships
@private
*/
normalizeRelationships: function(type, hash) {
var payloadKey;
if (this.keyForRelationship) {
type.eachRelationship(function(key, relationship) {
payloadKey = this.keyForRelationship(key, relationship.kind);
if (key === payloadKey) { return; }
if (!hash.hasOwnProperty(payloadKey)) { return; }
hash[key] = hash[payloadKey];
delete hash[payloadKey];
}, this);
}
},
/**
@method normalizeUsingDeclaredMapping
@private
*/
normalizeUsingDeclaredMapping: function(type, hash) {
var attrs = get(this, 'attrs'), payloadKey, key;
if (attrs) {
for (key in attrs) {
payloadKey = this._getMappedKey(key);
if (!hash.hasOwnProperty(payloadKey)) { continue; }
if (payloadKey !== key) {
hash[key] = hash[payloadKey];
delete hash[payloadKey];
}
}
}
},
/**
@method normalizeId
@private
*/
normalizeId: function(hash) {
var primaryKey = get(this, 'primaryKey');
if (primaryKey === 'id') { return; }
hash.id = hash[primaryKey];
delete hash[primaryKey];
},
/**
Looks up the property key that was set by the custom `attr` mapping
passed to the serializer.
@method _getMappedKey
@private
@param {String} key
@return {String} key
*/
_getMappedKey: function(key) {
var attrs = get(this, 'attrs');
var mappedKey;
if (attrs && attrs[key]) {
mappedKey = attrs[key];
//We need to account for both the {title: 'post_title'} and
//{title: {key: 'post_title'}} forms
if (mappedKey.key){
mappedKey = mappedKey.key;
}
if (typeof mappedKey === 'string'){
key = mappedKey;
}
}
return key;
},
/**
Check attrs.key.serialize property to inform if the `key`
can be serialized
@method _canSerialize
@private
@param {String} key
@return {boolean} true if the key can be serialized
*/
_canSerialize: function(key) {
var attrs = get(this, 'attrs');
return !attrs || !attrs[key] || attrs[key].serialize !== false;
},
// SERIALIZE
/**
Called when a record is saved in order to convert the
record into JSON.
By default, it creates a JSON object with a key for
each attribute and belongsTo relationship.
For example, consider this model:
```javascript
App.Comment = DS.Model.extend({
title: DS.attr(),
body: DS.attr(),
author: DS.belongsTo('user')
});
```
The default serialization would create a JSON object like:
```javascript
{
"title": "Rails is unagi",
"body": "Rails? Omakase? O_O",
"author": 12
}
```
By default, attributes are passed through as-is, unless
you specified an attribute type (`DS.attr('date')`). If
you specify a transform, the JavaScript value will be
serialized when inserted into the JSON hash.
By default, belongs-to relationships are converted into
IDs when inserted into the JSON hash.
## IDs
`serialize` takes an options hash with a single option:
`includeId`. If this option is `true`, `serialize` will,
by default include the ID in the JSON object it builds.
The adapter passes in `includeId: true` when serializing
a record for `createRecord`, but not for `updateRecord`.
## Customization
Your server may expect a different JSON format than the
built-in serialization format.
In that case, you can implement `serialize` yourself and
return a JSON hash of your choosing.
```javascript
App.PostSerializer = DS.JSONSerializer.extend({
serialize: function(post, options) {
var json = {
POST_TTL: post.get('title'),
POST_BDY: post.get('body'),
POST_CMS: post.get('comments').mapBy('id')
}
if (options.includeId) {
json.POST_ID_ = post.get('id');
}
return json;
}
});
```
## Customizing an App-Wide Serializer
If you want to define a serializer for your entire
application, you'll probably want to use `eachAttribute`
and `eachRelationship` on the record.
```javascript
App.ApplicationSerializer = DS.JSONSerializer.extend({
serialize: function(record, options) {
var json = {};
record.eachAttribute(function(name) {
json[serverAttributeName(name)] = record.get(name);
})
record.eachRelationship(function(name, relationship) {
if (relationship.kind === 'hasMany') {
json[serverHasManyName(name)] = record.get(name).mapBy('id');
}
});
if (options.includeId) {
json.ID_ = record.get('id');
}
return json;
}
});
function serverAttributeName(attribute) {
return attribute.underscore().toUpperCase();
}
function serverHasManyName(name) {
return serverAttributeName(name.singularize()) + "_IDS";
}
```
This serializer will generate JSON that looks like this:
```javascript
{
"TITLE": "Rails is omakase",
"BODY": "Yep. Omakase.",
"COMMENT_IDS": [ 1, 2, 3 ]
}
```
## Tweaking the Default JSON
If you just want to do some small tweaks on the default JSON,
you can call super first and make the tweaks on the returned
JSON.
```javascript
App.PostSerializer = DS.JSONSerializer.extend({
serialize: function(record, options) {
var json = this._super.apply(this, arguments);
json.subject = json.title;
delete json.title;
return json;
}
});
```
@method serialize
@param {subclass of DS.Model} record
@param {Object} options
@return {Object} json
*/
serialize: function(record, options) {
var json = {};
if (options && options.includeId) {
var id = get(record, 'id');
if (id) {
json[get(this, 'primaryKey')] = id;
}
}
record.eachAttribute(function(key, attribute) {
this.serializeAttribute(record, json, key, attribute);
}, this);
record.eachRelationship(function(key, relationship) {
if (relationship.kind === 'belongsTo') {
this.serializeBelongsTo(record, json, relationship);
} else if (relationship.kind === 'hasMany') {
this.serializeHasMany(record, json, relationship);
}
}, this);
return json;
},
/**
You can use this method to customize how a serialized record is added to the complete
JSON hash to be sent to the server. By default the JSON Serializer does not namespace
the payload and just sends the raw serialized JSON object.
If your server expects namespaced keys, you should consider using the RESTSerializer.
Otherwise you can override this method to customize how the record is added to the hash.
For example, your server may expect underscored root objects.
```js
App.ApplicationSerializer = DS.RESTSerializer.extend({
serializeIntoHash: function(data, type, record, options) {
var root = Ember.String.decamelize(type.typeKey);
data[root] = this.serialize(record, options);
}
});
```
@method serializeIntoHash
@param {Object} hash
@param {subclass of DS.Model} type
@param {DS.Model} record
@param {Object} options
*/
serializeIntoHash: function(hash, type, record, options) {
merge(hash, this.serialize(record, options));
},
/**
`serializeAttribute` can be used to customize how `DS.attr`
properties are serialized
For example if you wanted to ensure all your attributes were always
serialized as properties on an `attributes` object you could
write:
```javascript
App.ApplicationSerializer = DS.JSONSerializer.extend({
serializeAttribute: function(record, json, key, attributes) {
json.attributes = json.attributes || {};
this._super(record, json.attributes, key, attributes);
}
});
```
@method serializeAttribute
@param {DS.Model} record
@param {Object} json
@param {String} key
@param {Object} attribute
*/
serializeAttribute: function(record, json, key, attribute) {
var type = attribute.type;
if (this._canSerialize(key)) {
var value = get(record, key);
if (type) {
var transform = this.transformFor(type);
value = transform.serialize(value);
}
// if provided, use the mapping provided by `attrs` in
// the serializer
var payloadKey = this._getMappedKey(key);
if (payloadKey === key && this.keyForAttribute) {
payloadKey = this.keyForAttribute(key);
}
json[payloadKey] = value;
}
},
/**
`serializeBelongsTo` can be used to customize how `DS.belongsTo`
properties are serialized.
Example
```javascript
App.PostSerializer = DS.JSONSerializer.extend({
serializeBelongsTo: function(record, json, relationship) {
var key = relationship.key;
var belongsTo = get(record, key);
key = this.keyForRelationship ? this.keyForRelationship(key, "belongsTo") : key;
json[key] = Ember.isNone(belongsTo) ? belongsTo : belongsTo.toJSON();
}
});
```
@method serializeBelongsTo
@param {DS.Model} record
@param {Object} json
@param {Object} relationship
*/
serializeBelongsTo: function(record, json, relationship) {
var key = relationship.key;
if (this._canSerialize(key)) {
var belongsTo = get(record, key);
// if provided, use the mapping provided by `attrs` in
// the serializer
var payloadKey = this._getMappedKey(key);
if (payloadKey === key && this.keyForRelationship) {
payloadKey = this.keyForRelationship(key, "belongsTo");
}
//Need to check whether the id is there for new&async records
if (isNone(belongsTo) || isNone(get(belongsTo, 'id'))) {
json[payloadKey] = null;
} else {
json[payloadKey] = get(belongsTo, 'id');
}
if (relationship.options.polymorphic) {
this.serializePolymorphicType(record, json, relationship);
}
}
},
/**
`serializeHasMany` can be used to customize how `DS.hasMany`
properties are serialized.
Example
```javascript
App.PostSerializer = DS.JSONSerializer.extend({
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
if (key === 'comments') {
return;
} else {
this._super.apply(this, arguments);
}
}
});
```
@method serializeHasMany
@param {DS.Model} record
@param {Object} json
@param {Object} relationship
*/
serializeHasMany: function(record, json, relationship) {
var key = relationship.key;
if (this._canSerialize(key)) {
var payloadKey;
// if provided, use the mapping provided by `attrs` in
// the serializer
payloadKey = this._getMappedKey(key);
if (payloadKey === key && this.keyForRelationship) {
payloadKey = this.keyForRelationship(key, "hasMany");
}
var relationshipType = record.constructor.determineRelationshipType(relationship);
if (relationshipType === 'manyToNone' || relationshipType === 'manyToMany') {
json[payloadKey] = get(record, key).mapBy('id');
// TODO support for polymorphic manyToNone and manyToMany relationships
}
}
},
/**
You can use this method to customize how polymorphic objects are
serialized. Objects are considered to be polymorphic if
`{polymorphic: true}` is pass as the second argument to the
`DS.belongsTo` function.
Example
```javascript
App.CommentSerializer = DS.JSONSerializer.extend({
serializePolymorphicType: function(record, json, relationship) {
var key = relationship.key,
belongsTo = get(record, key);
key = this.keyForAttribute ? this.keyForAttribute(key) : key;
if (Ember.isNone(belongsTo)) {
json[key + "_type"] = null;
} else {
json[key + "_type"] = belongsTo.constructor.typeKey;
}
}
});
```
@method serializePolymorphicType
@param {DS.Model} record
@param {Object} json
@param {Object} relationship
*/
serializePolymorphicType: Ember.K,
// EXTRACT
/**
The `extract` method is used to deserialize payload data from the
server. By default the `JSONSerializer` does not push the records
into the store. However records that subclass `JSONSerializer`
such as the `RESTSerializer` may push records into the store as
part of the extract call.
This method delegates to a more specific extract method based on
the `requestType`.
Example
```javascript
var get = Ember.get;
socket.on('message', function(message) {
var modelName = message.model;
var data = message.data;
var type = store.modelFor(modelName);
var serializer = store.serializerFor(type.typeKey);
var record = serializer.extract(store, type, data, get(data, 'id'), 'single');
store.push(modelName, record);
});
```
@method extract
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Object} json The deserialized payload
*/
extract: function(store, type, payload, id, requestType) {
this.extractMeta(store, type, payload);
var specificExtract = "extract" + requestType.charAt(0).toUpperCase() + requestType.substr(1);
return this[specificExtract](store, type, payload, id, requestType);
},
/**
`extractFindAll` is a hook into the extract method used when a
call is made to `DS.Store#findAll`. By default this method is an
alias for [extractArray](#method_extractArray).
@method extractFindAll
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Array} array An array of deserialized objects
*/
extractFindAll: function(store, type, payload, id, requestType){
return this.extractArray(store, type, payload, id, requestType);
},
/**
`extractFindQuery` is a hook into the extract method used when a
call is made to `DS.Store#findQuery`. By default this method is an
alias for [extractArray](#method_extractArray).
@method extractFindQuery
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Array} array An array of deserialized objects
*/
extractFindQuery: function(store, type, payload, id, requestType){
return this.extractArray(store, type, payload, id, requestType);
},
/**
`extractFindMany` is a hook into the extract method used when a
call is made to `DS.Store#findMany`. By default this method is
alias for [extractArray](#method_extractArray).
@method extractFindMany
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Array} array An array of deserialized objects
*/
extractFindMany: function(store, type, payload, id, requestType){
return this.extractArray(store, type, payload, id, requestType);
},
/**
`extractFindHasMany` is a hook into the extract method used when a
call is made to `DS.Store#findHasMany`. By default this method is
alias for [extractArray](#method_extractArray).
@method extractFindHasMany
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Array} array An array of deserialized objects
*/
extractFindHasMany: function(store, type, payload, id, requestType){
return this.extractArray(store, type, payload, id, requestType);
},
/**
`extractCreateRecord` is a hook into the extract method used when a
call is made to `DS.Store#createRecord`. By default this method is
alias for [extractSave](#method_extractSave).
@method extractCreateRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Object} json The deserialized payload
*/
extractCreateRecord: function(store, type, payload, id, requestType) {
return this.extractSave(store, type, payload, id, requestType);
},
/**
`extractUpdateRecord` is a hook into the extract method used when
a call is made to `DS.Store#update`. By default this method is alias
for [extractSave](#method_extractSave).
@method extractUpdateRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Object} json The deserialized payload
*/
extractUpdateRecord: function(store, type, payload, id, requestType) {
return this.extractSave(store, type, payload, id, requestType);
},
/**
`extractDeleteRecord` is a hook into the extract method used when
a call is made to `DS.Store#deleteRecord`. By default this method is
alias for [extractSave](#method_extractSave).
@method extractDeleteRecord
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Object} json The deserialized payload
*/
extractDeleteRecord: function(store, type, payload, id, requestType) {
return this.extractSave(store, type, payload, id, requestType);
},
/**
`extractFind` is a hook into the extract method used when
a call is made to `DS.Store#find`. By default this method is
alias for [extractSingle](#method_extractSingle).
@method extractFind
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Object} json The deserialized payload
*/
extractFind: function(store, type, payload, id, requestType) {
return this.extractSingle(store, type, payload, id, requestType);
},
/**
`extractFindBelongsTo` is a hook into the extract method used when
a call is made to `DS.Store#findBelongsTo`. By default this method is
alias for [extractSingle](#method_extractSingle).
@method extractFindBelongsTo
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Object} json The deserialized payload
*/
extractFindBelongsTo: function(store, type, payload, id, requestType) {
return this.extractSingle(store, type, payload, id, requestType);
},
/**
`extractSave` is a hook into the extract method used when a call
is made to `DS.Model#save`. By default this method is alias
for [extractSingle](#method_extractSingle).
@method extractSave
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Object} json The deserialized payload
*/
extractSave: function(store, type, payload, id, requestType) {
return this.extractSingle(store, type, payload, id, requestType);
},
/**
`extractSingle` is used to deserialize a single record returned
from the adapter.
Example
```javascript
App.PostSerializer = DS.JSONSerializer.extend({
extractSingle: function(store, type, payload) {
payload.comments = payload._embedded.comment;
delete payload._embedded;
return this._super(store, type, payload);
},
});
```
@method extractSingle
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Object} json The deserialized payload
*/
extractSingle: function(store, type, payload, id, requestType) {
payload = this.normalizePayload(payload);
return this.normalize(type, payload);
},
/**
`extractArray` is used to deserialize an array of records
returned from the adapter.
Example
```javascript
App.PostSerializer = DS.JSONSerializer.extend({
extractArray: function(store, type, payload) {
return payload.map(function(json) {
return this.extractSingle(store, type, json);
}, this);
}
});
```
@method extractArray
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
@param {String or Number} id
@param {String} requestType
@return {Array} array An array of deserialized objects
*/
extractArray: function(store, type, arrayPayload, id, requestType) {
var normalizedPayload = this.normalizePayload(arrayPayload);
var serializer = this;
return map.call(normalizedPayload, function(singlePayload) {
return serializer.normalize(type, singlePayload);
});
},
/**
`extractMeta` is used to deserialize any meta information in the
adapter payload. By default Ember Data expects meta information to
be located on the `meta` property of the payload object.
Example
```javascript
App.PostSerializer = DS.JSONSerializer.extend({
extractMeta: function(store, type, payload) {
if (payload && payload._pagination) {
store.metaForType(type, payload._pagination);
delete payload._pagination;
}
}
});
```
@method extractMeta
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} payload
*/
extractMeta: function(store, type, payload) {
if (payload && payload.meta) {
store.metaForType(type, payload.meta);
delete payload.meta;
}
},
/**
`keyForAttribute` can be used to define rules for how to convert an
attribute name in your model to a key in your JSON.
Example
```javascript
App.ApplicationSerializer = DS.RESTSerializer.extend({
keyForAttribute: function(attr) {
return Ember.String.underscore(attr).toUpperCase();
}
});
```
@method keyForAttribute
@param {String} key
@return {String} normalized key
*/
keyForAttribute: function(key){
return key;
},
/**
`keyForRelationship` can be used to define a custom key when
serializing relationship properties. By default `JSONSerializer`
does not provide an implementation of this method.
Example
```javascript
App.PostSerializer = DS.JSONSerializer.extend({
keyForRelationship: function(key, relationship) {
return 'rel_' + Ember.String.underscore(key);
}
});
```
@method keyForRelationship
@param {String} key
@param {String} relationship type
@return {String} normalized key
*/
keyForRelationship: function(key, type){
return key;
},
// HELPERS
/**
@method transformFor
@private
@param {String} attributeType
@param {Boolean} skipAssertion
@return {DS.Transform} transform
*/
transformFor: function(attributeType, skipAssertion) {
var transform = this.container.lookup('transform:' + attributeType);
Ember.assert("Unable to find transform for '" + attributeType + "'", skipAssertion || !!transform);
return transform;
}
});
});
define("ember-data/serializers/rest_serializer",
["ember-data/serializers/json_serializer","ember-inflector/system/string","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
/**
@module ember-data
*/
var JSONSerializer = __dependency1__["default"];
var get = Ember.get;
var forEach = Ember.ArrayPolyfills.forEach;
var map = Ember.ArrayPolyfills.map;
var camelize = Ember.String.camelize;
var singularize = __dependency2__.singularize;
function coerceId(id) {
return id == null ? null : id + '';
}
/**
Normally, applications will use the `RESTSerializer` by implementing
the `normalize` method and individual normalizations under
`normalizeHash`.
This allows you to do whatever kind of munging you need, and is
especially useful if your server is inconsistent and you need to
do munging differently for many different kinds of responses.
See the `normalize` documentation for more information.
## Across the Board Normalization
There are also a number of hooks that you might find useful to define
across-the-board rules for your payload. These rules will be useful
if your server is consistent, or if you're building an adapter for
an infrastructure service, like Parse, and want to encode service
conventions.
For example, if all of your keys are underscored and all-caps, but
otherwise consistent with the names you use in your models, you
can implement across-the-board rules for how to convert an attribute
name in your model to a key in your JSON.
```js
App.ApplicationSerializer = DS.RESTSerializer.extend({
keyForAttribute: function(attr) {
return Ember.String.underscore(attr).toUpperCase();
}
});
```
You can also implement `keyForRelationship`, which takes the name
of the relationship as the first parameter, and the kind of
relationship (`hasMany` or `belongsTo`) as the second parameter.
@class RESTSerializer
@namespace DS
@extends DS.JSONSerializer
*/
var RESTSerializer = JSONSerializer.extend({
/**
If you want to do normalizations specific to some part of the payload, you
can specify those under `normalizeHash`.
For example, given the following json where the the `IDs` under
`"comments"` are provided as `_id` instead of `id`.
```javascript
{
"post": {
"id": 1,
"title": "Rails is omakase",
"comments": [ 1, 2 ]
},
"comments": [{
"_id": 1,
"body": "FIRST"
}, {
"_id": 2,
"body": "Rails is unagi"
}]
}
```
You use `normalizeHash` to normalize just the comments:
```javascript
App.PostSerializer = DS.RESTSerializer.extend({
normalizeHash: {
comments: function(hash) {
hash.id = hash._id;
delete hash._id;
return hash;
}
}
});
```
The key under `normalizeHash` is usually just the original key
that was in the original payload. However, key names will be
impacted by any modifications done in the `normalizePayload`
method. The `DS.RESTSerializer`'s default implementation makes no
changes to the payload keys.
@property normalizeHash
@type {Object}
@default undefined
*/
/**
Normalizes a part of the JSON payload returned by
the server. You should override this method, munge the hash
and call super if you have generic normalization to do.
It takes the type of the record that is being normalized
(as a DS.Model class), the property where the hash was
originally found, and the hash to normalize.
For example, if you have a payload that looks like this:
```js
{
"post": {
"id": 1,
"title": "Rails is omakase",
"comments": [ 1, 2 ]
},
"comments": [{
"id": 1,
"body": "FIRST"
}, {
"id": 2,
"body": "Rails is unagi"
}]
}
```
The `normalize` method will be called three times:
* With `App.Post`, `"posts"` and `{ id: 1, title: "Rails is omakase", ... }`
* With `App.Comment`, `"comments"` and `{ id: 1, body: "FIRST" }`
* With `App.Comment`, `"comments"` and `{ id: 2, body: "Rails is unagi" }`
You can use this method, for example, to normalize underscored keys to camelized
or other general-purpose normalizations.
If you want to do normalizations specific to some part of the payload, you
can specify those under `normalizeHash`.
For example, if the `IDs` under `"comments"` are provided as `_id` instead of
`id`, you can specify how to normalize just the comments:
```js
App.PostSerializer = DS.RESTSerializer.extend({
normalizeHash: {
comments: function(hash) {
hash.id = hash._id;
delete hash._id;
return hash;
}
}
});
```
The key under `normalizeHash` is just the original key that was in the original
payload.
@method normalize
@param {subclass of DS.Model} type
@param {Object} hash
@param {String} prop
@return {Object}
*/
normalize: function(type, hash, prop) {
this.normalizeId(hash);
this.normalizeAttributes(type, hash);
this.normalizeRelationships(type, hash);
this.normalizeUsingDeclaredMapping(type, hash);
if (this.normalizeHash && this.normalizeHash[prop]) {
this.normalizeHash[prop](hash);
}
this.applyTransforms(type, hash);
return hash;
},
/**
Called when the server has returned a payload representing
a single record, such as in response to a `find` or `save`.
It is your opportunity to clean up the server's response into the normalized
form expected by Ember Data.
If you want, you can just restructure the top-level of your payload, and
do more fine-grained normalization in the `normalize` method.
For example, if you have a payload like this in response to a request for
post 1:
```js
{
"id": 1,
"title": "Rails is omakase",
"_embedded": {
"comment": [{
"_id": 1,
"comment_title": "FIRST"
}, {
"_id": 2,
"comment_title": "Rails is unagi"
}]
}
}
```
You could implement a serializer that looks like this to get your payload
into shape:
```js
App.PostSerializer = DS.RESTSerializer.extend({
// First, restructure the top-level so it's organized by type
extractSingle: function(store, type, payload, id) {
var comments = payload._embedded.comment;
delete payload._embedded;
payload = { comments: comments, post: payload };
return this._super(store, type, payload, id);
},
normalizeHash: {
// Next, normalize individual comments, which (after `extract`)
// are now located under `comments`
comments: function(hash) {
hash.id = hash._id;
hash.title = hash.comment_title;
delete hash._id;
delete hash.comment_title;
return hash;
}
}
})
```
When you call super from your own implementation of `extractSingle`, the
built-in implementation will find the primary record in your normalized
payload and push the remaining records into the store.
The primary record is the single hash found under `post` or the first
element of the `posts` array.
The primary record has special meaning when the record is being created
for the first time or updated (`createRecord` or `updateRecord`). In
particular, it will update the properties of the record that was saved.
@method extractSingle
@param {DS.Store} store
@param {subclass of DS.Model} primaryType
@param {Object} payload
@param {String} recordId
@return {Object} the primary response to the original request
*/
extractSingle: function(store, primaryType, rawPayload, recordId) {
var payload = this.normalizePayload(rawPayload);
var primaryTypeName = primaryType.typeKey;
var primaryRecord;
for (var prop in payload) {
var typeName = this.typeForRoot(prop);
if (!store.modelFactoryFor(typeName)){
Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false);
continue;
}
var type = store.modelFor(typeName);
var isPrimary = type.typeKey === primaryTypeName;
var value = payload[prop];
// legacy support for singular resources
if (isPrimary && Ember.typeOf(value) !== "array" ) {
primaryRecord = this.normalize(primaryType, value, prop);
continue;
}
/*jshint loopfunc:true*/
forEach.call(value, function(hash) {
var typeName = this.typeForRoot(prop);
var type = store.modelFor(typeName);
var typeSerializer = store.serializerFor(type);
hash = typeSerializer.normalize(type, hash, prop);
var isFirstCreatedRecord = isPrimary && !recordId && !primaryRecord;
var isUpdatedRecord = isPrimary && coerceId(hash.id) === recordId;
// find the primary record.
//
// It's either:
// * the record with the same ID as the original request
// * in the case of a newly created record that didn't have an ID, the first
// record in the Array
if (isFirstCreatedRecord || isUpdatedRecord) {
primaryRecord = hash;
} else {
store.push(typeName, hash);
}
}, this);
}
return primaryRecord;
},
/**
Called when the server has returned a payload representing
multiple records, such as in response to a `findAll` or `findQuery`.
It is your opportunity to clean up the server's response into the normalized
form expected by Ember Data.
If you want, you can just restructure the top-level of your payload, and
do more fine-grained normalization in the `normalize` method.
For example, if you have a payload like this in response to a request for
all posts:
```js
{
"_embedded": {
"post": [{
"id": 1,
"title": "Rails is omakase"
}, {
"id": 2,
"title": "The Parley Letter"
}],
"comment": [{
"_id": 1,
"comment_title": "Rails is unagi"
"post_id": 1
}, {
"_id": 2,
"comment_title": "Don't tread on me",
"post_id": 2
}]
}
}
```
You could implement a serializer that looks like this to get your payload
into shape:
```js
App.PostSerializer = DS.RESTSerializer.extend({
// First, restructure the top-level so it's organized by type
// and the comments are listed under a post's `comments` key.
extractArray: function(store, type, payload) {
var posts = payload._embedded.post;
var comments = [];
var postCache = {};
posts.forEach(function(post) {
post.comments = [];
postCache[post.id] = post;
});
payload._embedded.comment.forEach(function(comment) {
comments.push(comment);
postCache[comment.post_id].comments.push(comment);
delete comment.post_id;
});
payload = { comments: comments, posts: payload };
return this._super(store, type, payload);
},
normalizeHash: {
// Next, normalize individual comments, which (after `extract`)
// are now located under `comments`
comments: function(hash) {
hash.id = hash._id;
hash.title = hash.comment_title;
delete hash._id;
delete hash.comment_title;
return hash;
}
}
})
```
When you call super from your own implementation of `extractArray`, the
built-in implementation will find the primary array in your normalized
payload and push the remaining records into the store.
The primary array is the array found under `posts`.
The primary record has special meaning when responding to `findQuery`
or `findHasMany`. In particular, the primary array will become the
list of records in the record array that kicked off the request.
If your primary array contains secondary (embedded) records of the same type,
you cannot place these into the primary array `posts`. Instead, place the
secondary items into an underscore prefixed property `_posts`, which will
push these items into the store and will not affect the resulting query.
@method extractArray
@param {DS.Store} store
@param {subclass of DS.Model} primaryType
@param {Object} payload
@return {Array} The primary array that was returned in response
to the original query.
*/
extractArray: function(store, primaryType, rawPayload) {
var payload = this.normalizePayload(rawPayload);
var primaryTypeName = primaryType.typeKey;
var primaryArray;
for (var prop in payload) {
var typeKey = prop;
var forcedSecondary = false;
if (prop.charAt(0) === '_') {
forcedSecondary = true;
typeKey = prop.substr(1);
}
var typeName = this.typeForRoot(typeKey);
if (!store.modelFactoryFor(typeName)) {
Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false);
continue;
}
var type = store.modelFor(typeName);
var typeSerializer = store.serializerFor(type);
var isPrimary = (!forcedSecondary && (type.typeKey === primaryTypeName));
/*jshint loopfunc:true*/
var normalizedArray = map.call(payload[prop], function(hash) {
return typeSerializer.normalize(type, hash, prop);
}, this);
if (isPrimary) {
primaryArray = normalizedArray;
} else {
store.pushMany(typeName, normalizedArray);
}
}
return primaryArray;
},
/**
This method allows you to push a payload containing top-level
collections of records organized per type.
```js
{
"posts": [{
"id": "1",
"title": "Rails is omakase",
"author", "1",
"comments": [ "1" ]
}],
"comments": [{
"id": "1",
"body": "FIRST"
}],
"users": [{
"id": "1",
"name": "@d2h"
}]
}
```
It will first normalize the payload, so you can use this to push
in data streaming in from your server structured the same way
that fetches and saves are structured.
@method pushPayload
@param {DS.Store} store
@param {Object} payload
*/
pushPayload: function(store, rawPayload) {
var payload = this.normalizePayload(rawPayload);
for (var prop in payload) {
var typeName = this.typeForRoot(prop);
if (!store.modelFactoryFor(typeName, prop)){
Ember.warn(this.warnMessageNoModelForKey(prop, typeName), false);
continue;
}
var type = store.modelFor(typeName);
var typeSerializer = store.serializerFor(type);
/*jshint loopfunc:true*/
var normalizedArray = map.call(Ember.makeArray(payload[prop]), function(hash) {
return typeSerializer.normalize(type, hash, prop);
}, this);
store.pushMany(typeName, normalizedArray);
}
},
/**
This method is used to convert each JSON root key in the payload
into a typeKey that it can use to look up the appropriate model for
that part of the payload. By default the typeKey for a model is its
name in camelCase, so if your JSON root key is 'fast-car' you would
use typeForRoot to convert it to 'fastCar' so that Ember Data finds
the `FastCar` model.
If you diverge from this norm you should also consider changes to
store._normalizeTypeKey as well.
For example, your server may return prefixed root keys like so:
```js
{
"response-fast-car": {
"id": "1",
"name": "corvette"
}
}
```
In order for Ember Data to know that the model corresponding to
the 'response-fast-car' hash is `FastCar` (typeKey: 'fastCar'),
you can override typeForRoot to convert 'response-fast-car' to
'fastCar' like so:
```js
App.ApplicationSerializer = DS.RESTSerializer.extend({
typeForRoot: function(root) {
// 'response-fast-car' should become 'fast-car'
var subRoot = root.substring(9);
// _super normalizes 'fast-car' to 'fastCar'
return this._super(subRoot);
}
});
```
@method typeForRoot
@param {String} key
@return {String} the model's typeKey
*/
typeForRoot: function(key) {
return camelize(singularize(key));
},
// SERIALIZE
/**
Called when a record is saved in order to convert the
record into JSON.
By default, it creates a JSON object with a key for
each attribute and belongsTo relationship.
For example, consider this model:
```js
App.Comment = DS.Model.extend({
title: DS.attr(),
body: DS.attr(),
author: DS.belongsTo('user')
});
```
The default serialization would create a JSON object like:
```js
{
"title": "Rails is unagi",
"body": "Rails? Omakase? O_O",
"author": 12
}
```
By default, attributes are passed through as-is, unless
you specified an attribute type (`DS.attr('date')`). If
you specify a transform, the JavaScript value will be
serialized when inserted into the JSON hash.
By default, belongs-to relationships are converted into
IDs when inserted into the JSON hash.
## IDs
`serialize` takes an options hash with a single option:
`includeId`. If this option is `true`, `serialize` will,
by default include the ID in the JSON object it builds.
The adapter passes in `includeId: true` when serializing
a record for `createRecord`, but not for `updateRecord`.
## Customization
Your server may expect a different JSON format than the
built-in serialization format.
In that case, you can implement `serialize` yourself and
return a JSON hash of your choosing.
```js
App.PostSerializer = DS.RESTSerializer.extend({
serialize: function(post, options) {
var json = {
POST_TTL: post.get('title'),
POST_BDY: post.get('body'),
POST_CMS: post.get('comments').mapBy('id')
}
if (options.includeId) {
json.POST_ID_ = post.get('id');
}
return json;
}
});
```
## Customizing an App-Wide Serializer
If you want to define a serializer for your entire
application, you'll probably want to use `eachAttribute`
and `eachRelationship` on the record.
```js
App.ApplicationSerializer = DS.RESTSerializer.extend({
serialize: function(record, options) {
var json = {};
record.eachAttribute(function(name) {
json[serverAttributeName(name)] = record.get(name);
})
record.eachRelationship(function(name, relationship) {
if (relationship.kind === 'hasMany') {
json[serverHasManyName(name)] = record.get(name).mapBy('id');
}
});
if (options.includeId) {
json.ID_ = record.get('id');
}
return json;
}
});
function serverAttributeName(attribute) {
return attribute.underscore().toUpperCase();
}
function serverHasManyName(name) {
return serverAttributeName(name.singularize()) + "_IDS";
}
```
This serializer will generate JSON that looks like this:
```js
{
"TITLE": "Rails is omakase",
"BODY": "Yep. Omakase.",
"COMMENT_IDS": [ 1, 2, 3 ]
}
```
## Tweaking the Default JSON
If you just want to do some small tweaks on the default JSON,
you can call super first and make the tweaks on the returned
JSON.
```js
App.PostSerializer = DS.RESTSerializer.extend({
serialize: function(record, options) {
var json = this._super(record, options);
json.subject = json.title;
delete json.title;
return json;
}
});
```
@method serialize
@param {subclass of DS.Model} record
@param {Object} options
@return {Object} json
*/
serialize: function(record, options) {
return this._super.apply(this, arguments);
},
/**
You can use this method to customize the root keys serialized into the JSON.
By default the REST Serializer sends the typeKey of a model, which is a camelized
version of the name.
For example, your server may expect underscored root objects.
```js
App.ApplicationSerializer = DS.RESTSerializer.extend({
serializeIntoHash: function(data, type, record, options) {
var root = Ember.String.decamelize(type.typeKey);
data[root] = this.serialize(record, options);
}
});
```
@method serializeIntoHash
@param {Object} hash
@param {subclass of DS.Model} type
@param {DS.Model} record
@param {Object} options
*/
serializeIntoHash: function(hash, type, record, options) {
hash[type.typeKey] = this.serialize(record, options);
},
/**
You can use this method to customize how polymorphic objects are serialized.
By default the JSON Serializer creates the key by appending `Type` to
the attribute and value from the model's camelcased model name.
@method serializePolymorphicType
@param {DS.Model} record
@param {Object} json
@param {Object} relationship
*/
serializePolymorphicType: function(record, json, relationship) {
var key = relationship.key;
var belongsTo = get(record, key);
key = this.keyForAttribute ? this.keyForAttribute(key) : key;
if (Ember.isNone(belongsTo)) {
json[key + "Type"] = null;
} else {
json[key + "Type"] = Ember.String.camelize(belongsTo.constructor.typeKey);
}
}
});
Ember.runInDebug(function(){
RESTSerializer.reopen({
warnMessageNoModelForKey: function(prop, typeKey){
return 'Encountered "' + prop + '" in payload, but no model was found for model name "' + typeKey + '" (resolved model name using ' + this.constructor.toString() + '.typeForRoot("' + prop + '"))';
}
});
});
__exports__["default"] = RESTSerializer;
});
define("ember-data/setup-container",
["ember-data/initializers/store","ember-data/initializers/transforms","ember-data/initializers/store_injections","ember-data/initializers/data_adapter","activemodel-adapter/setup-container","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) {
"use strict";
var initializeStore = __dependency1__["default"];
var initializeTransforms = __dependency2__["default"];
var initializeStoreInjections = __dependency3__["default"];
var initializeDataAdapter = __dependency4__["default"];
var setupActiveModelContainer = __dependency5__["default"];
__exports__["default"] = function setupContainer(container, application){
// application is not a required argument. This ensures
// testing setups can setup a container without booting an
// entire ember application.
initializeDataAdapter(container, application);
initializeTransforms(container, application);
initializeStoreInjections(container, application);
initializeStore(container, application);
setupActiveModelContainer(container, application);
};
});
define("ember-data/system/adapter",
["exports"],
function(__exports__) {
"use strict";
/**
@module ember-data
*/
var get = Ember.get;
var errorProps = [
'description',
'fileName',
'lineNumber',
'message',
'name',
'number',
'stack'
];
/**
A `DS.InvalidError` is used by an adapter to signal the external API
was unable to process a request because the content was not
semantically correct or meaningful per the API. Usually this means a
record failed some form of server side validation. When a promise
from an adapter is rejected with a `DS.InvalidError` the record will
transition to the `invalid` state and the errors will be set to the
`errors` property on the record.
Example
```javascript
App.ApplicationAdapter = DS.RESTAdapter.extend({
ajaxError: function(jqXHR) {
var error = this._super(jqXHR);
if (jqXHR && jqXHR.status === 422) {
var jsonErrors = Ember.$.parseJSON(jqXHR.responseText)["errors"];
return new DS.InvalidError(jsonErrors);
} else {
return error;
}
}
});
```
The `DS.InvalidError` must be constructed with a single object whose
keys are the invalid model properties, and whose values are the
corresponding error messages. For example:
```javascript
return new DS.InvalidError({
length: 'Must be less than 15',
name: 'Must not be blank
});
```
@class InvalidError
@namespace DS
*/
function InvalidError(errors) {
var tmp = Error.prototype.constructor.call(this, "The backend rejected the commit because it was invalid: " + Ember.inspect(errors));
this.errors = errors;
for (var i=0, l=errorProps.length; i<l; i++) {
this[errorProps[i]] = tmp[errorProps[i]];
}
}
InvalidError.prototype = Ember.create(Error.prototype);
/**
An adapter is an object that receives requests from a store and
translates them into the appropriate action to take against your
persistence layer. The persistence layer is usually an HTTP API, but
may be anything, such as the browser's local storage. Typically the
adapter is not invoked directly instead its functionality is accessed
through the `store`.
### Creating an Adapter
Create a new subclass of `DS.Adapter`, then assign
it to the `ApplicationAdapter` property of the application.
```javascript
var MyAdapter = DS.Adapter.extend({
// ...your code here
});
App.ApplicationAdapter = MyAdapter;
```
Model-specific adapters can be created by assigning your adapter
class to the `ModelName` + `Adapter` property of the application.
```javascript
var MyPostAdapter = DS.Adapter.extend({
// ...Post-specific adapter code goes here
});
App.PostAdapter = MyPostAdapter;
```
`DS.Adapter` is an abstract base class that you should override in your
application to customize it for your backend. The minimum set of methods
that you should implement is:
* `find()`
* `createRecord()`
* `updateRecord()`
* `deleteRecord()`
* `findAll()`
* `findQuery()`
To improve the network performance of your application, you can optimize
your adapter by overriding these lower-level methods:
* `findMany()`
For an example implementation, see `DS.RESTAdapter`, the
included REST adapter.
@class Adapter
@namespace DS
@extends Ember.Object
*/
var Adapter = Ember.Object.extend({
/**
If you would like your adapter to use a custom serializer you can
set the `defaultSerializer` property to be the name of the custom
serializer.
Note the `defaultSerializer` serializer has a lower priority than
a model specific serializer (i.e. `PostSerializer`) or the
`application` serializer.
```javascript
var DjangoAdapter = DS.Adapter.extend({
defaultSerializer: 'django'
});
```
@property defaultSerializer
@type {String}
*/
/**
The `find()` method is invoked when the store is asked for a record that
has not previously been loaded. In response to `find()` being called, you
should query your persistence layer for a record with the given ID. Once
found, you can asynchronously call the store's `push()` method to push
the record into the store.
Here is an example `find` implementation:
```javascript
App.ApplicationAdapter = DS.Adapter.extend({
find: function(store, type, id) {
var url = [type.typeKey, id].join('/');
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.getJSON(url).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
}
});
```
@method find
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {String} id
@return {Promise} promise
*/
find: Ember.required(Function),
/**
The `findAll()` method is called when you call `find` on the store
without an ID (i.e. `store.find('post')`).
Example
```javascript
App.ApplicationAdapter = DS.Adapter.extend({
findAll: function(store, type, sinceToken) {
var url = type;
var query = { since: sinceToken };
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.getJSON(url, query).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
}
});
```
@private
@method findAll
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {String} sinceToken
@return {Promise} promise
*/
findAll: null,
/**
This method is called when you call `find` on the store with a
query object as the second parameter (i.e. `store.find('person', {
page: 1 })`).
Example
```javascript
App.ApplicationAdapter = DS.Adapter.extend({
findQuery: function(store, type, query) {
var url = type;
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.getJSON(url, query).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
}
});
```
@private
@method findQuery
@param {DS.Store} store
@param {subclass of DS.Model} type
@param {Object} query
@param {DS.AdapterPopulatedRecordArray} recordArray
@return {Promise} promise
*/
findQuery: null,
/**
If the globally unique IDs for your records should be generated on the client,
implement the `generateIdForRecord()` method. This method will be invoked
each time you create a new record, and the value returned from it will be
assigned to the record's `primaryKey`.
Most traditional REST-like HTTP APIs will not use this method. Instead, the ID
of the record will be set by the server, and your adapter will update the store
with the new ID when it calls `didCreateRecord()`. Only implement this method if
you intend to generate record IDs on the client-side.
The `generateIdForRecord()` method will be invoked with the requesting store as
the first parameter and the newly created record as the second parameter:
```javascript
generateIdForRecord: function(store, record) {
var uuid = App.generateUUIDWithStatisticallyLowOddsOfCollision();
return uuid;
}
```
@method generateIdForRecord
@param {DS.Store} store
@param {DS.Model} record
@return {String|Number} id
*/
generateIdForRecord: null,
/**
Proxies to the serializer's `serialize` method.
Example
```javascript
App.ApplicationAdapter = DS.Adapter.extend({
createRecord: function(store, type, record) {
var data = this.serialize(record, { includeId: true });
var url = type;
// ...
}
});
```
@method serialize
@param {DS.Model} record
@param {Object} options
@return {Object} serialized record
*/
serialize: function(record, options) {
return get(record, 'store').serializerFor(record.constructor.typeKey).serialize(record, options);
},
/**
Implement this method in a subclass to handle the creation of
new records.
Serializes the record and send it to the server.
Example
```javascript
App.ApplicationAdapter = DS.Adapter.extend({
createRecord: function(store, type, record) {
var data = this.serialize(record, { includeId: true });
var url = type;
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.ajax({
type: 'POST',
url: url,
dataType: 'json',
data: data
}).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
}
});
```
@method createRecord
@param {DS.Store} store
@param {subclass of DS.Model} type the DS.Model class of the record
@param {DS.Model} record
@return {Promise} promise
*/
createRecord: Ember.required(Function),
/**
Implement this method in a subclass to handle the updating of
a record.
Serializes the record update and send it to the server.
Example
```javascript
App.ApplicationAdapter = DS.Adapter.extend({
updateRecord: function(store, type, record) {
var data = this.serialize(record, { includeId: true });
var id = record.get('id');
var url = [type, id].join('/');
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.ajax({
type: 'PUT',
url: url,
dataType: 'json',
data: data
}).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
}
});
```
@method updateRecord
@param {DS.Store} store
@param {subclass of DS.Model} type the DS.Model class of the record
@param {DS.Model} record
@return {Promise} promise
*/
updateRecord: Ember.required(Function),
/**
Implement this method in a subclass to handle the deletion of
a record.
Sends a delete request for the record to the server.
Example
```javascript
App.ApplicationAdapter = DS.Adapter.extend({
deleteRecord: function(store, type, record) {
var data = this.serialize(record, { includeId: true });
var id = record.get('id');
var url = [type, id].join('/');
return new Ember.RSVP.Promise(function(resolve, reject) {
jQuery.ajax({
type: 'DELETE',
url: url,
dataType: 'json',
data: data
}).then(function(data) {
Ember.run(null, resolve, data);
}, function(jqXHR) {
jqXHR.then = null; // tame jQuery's ill mannered promises
Ember.run(null, reject, jqXHR);
});
});
}
});
```
@method deleteRecord
@param {DS.Store} store
@param {subclass of DS.Model} type the DS.Model class of the record
@param {DS.Model} record
@return {Promise} promise
*/
deleteRecord: Ember.required(Function),
/**
By default the store will try to coalesce all `fetchRecord` calls within the same runloop
into as few requests as possible by calling groupRecordsForFindMany and passing it into a findMany call.
You can opt out of this behaviour by either not implementing the findMany hook or by setting
coalesceFindRequests to false
@property coalesceFindRequests
@type {boolean}
*/
coalesceFindRequests: true,
/**
Find multiple records at once if coalesceFindRequests is true
@method findMany
@param {DS.Store} store
@param {subclass of DS.Model} type the DS.Model class of the records
@param {Array} ids
@param {Array} records
@return {Promise} promise
*/
/**
Organize records into groups, each of which is to be passed to separate
calls to `findMany`.
For example, if your api has nested URLs that depend on the parent, you will
want to group records by their parent.
The default implementation returns the records as a single group.
@method groupRecordsForFindMany
@param {Array} records
@return {Array} an array of arrays of records, each of which is to be
loaded separately by `findMany`.
*/
groupRecordsForFindMany: function (store, records) {
return [records];
}
});
__exports__.InvalidError = InvalidError;
__exports__.Adapter = Adapter;
__exports__["default"] = Adapter;
});
define("ember-data/system/container_proxy",
["exports"],
function(__exports__) {
"use strict";
/**
This is used internally to enable deprecation of container paths and provide
a decent message to the user indicating how to fix the issue.
@class ContainerProxy
@namespace DS
@private
*/
function ContainerProxy(container){
this.container = container;
}
ContainerProxy.prototype.aliasedFactory = function(path, preLookup) {
var _this = this;
return {create: function(){
if (preLookup) { preLookup(); }
return _this.container.lookup(path);
}};
};
ContainerProxy.prototype.registerAlias = function(source, dest, preLookup) {
var factory = this.aliasedFactory(dest, preLookup);
return this.container.register(source, factory);
};
ContainerProxy.prototype.registerDeprecation = function(deprecated, valid) {
var preLookupCallback = function(){
Ember.deprecate("You tried to look up '" + deprecated + "', " +
"but this has been deprecated in favor of '" + valid + "'.", false);
};
return this.registerAlias(deprecated, valid, preLookupCallback);
};
ContainerProxy.prototype.registerDeprecations = function(proxyPairs) {
var i, proxyPair, deprecated, valid;
for (i = proxyPairs.length; i > 0; i--) {
proxyPair = proxyPairs[i - 1];
deprecated = proxyPair['deprecated'];
valid = proxyPair['valid'];
this.registerDeprecation(deprecated, valid);
}
};
__exports__["default"] = ContainerProxy;
});
define("ember-data/system/debug",
["ember-data/system/debug/debug_info","ember-data/system/debug/debug_adapter","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
/**
@module ember-data
*/
var DebugAdapter = __dependency2__["default"];
__exports__["default"] = DebugAdapter;
});
define("ember-data/system/debug/debug_adapter",
["ember-data/system/model","exports"],
function(__dependency1__, __exports__) {
"use strict";
/**
@module ember-data
*/
var Model = __dependency1__.Model;
var get = Ember.get;
var capitalize = Ember.String.capitalize;
var underscore = Ember.String.underscore;
/**
Extend `Ember.DataAdapter` with ED specific code.
@class DebugAdapter
@namespace DS
@extends Ember.DataAdapter
@private
*/
__exports__["default"] = Ember.DataAdapter.extend({
getFilters: function() {
return [
{ name: 'isNew', desc: 'New' },
{ name: 'isModified', desc: 'Modified' },
{ name: 'isClean', desc: 'Clean' }
];
},
detect: function(klass) {