UNPKG

todomvc

Version:

> Helping you select an MV\* framework

1,681 lines (1,372 loc) 341 kB
/*! * @overview Ember Data * @copyright Copyright 2011-2014 Tilde Inc. and contributors. * Portions Copyright 2011 LivingSocial Inc. * @license Licensed under MIT license (see license.js) * @version 1.0.0-beta.7+canary.b45e23ba */ (function(global) { var define, requireModule, require, requirejs; (function() { var registry = {}, seen = {}; define = function(name, deps, callback) { registry[name] = { deps: deps, callback: callback }; }; requirejs = require = requireModule = function(name) { requirejs._eak_seen = registry; if (seen[name]) { return seen[name]; } seen[name] = {}; if (!registry[name]) { throw new Error("Could not find module " + name); } var mod = registry[name], deps = mod.deps, callback = mod.callback, reified = [], exports; for (var i=0, l=deps.length; i<l; i++) { if (deps[i] === 'exports') { reified.push(exports = {}); } else { reified.push(requireModule(resolve(deps[i]))); } } var value = callback.apply(this, reified); return seen[name] = exports || value; function resolve(child) { if (child.charAt(0) !== '.') { return child; } var parts = child.split("/"); var parentBase = name.split("/").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("/"); } }; })(); define("activemodel-adapter/lib/initializers", ["../../ember-data/lib/system/container_proxy","./system/active_model_serializer","./system/active_model_adapter"], function(__dependency1__, __dependency2__, __dependency3__) { "use strict"; var ContainerProxy = __dependency1__["default"]; var ActiveModelSerializer = __dependency2__["default"]; var ActiveModelAdapter = __dependency3__["default"]; Ember.onLoad('Ember.Application', function(Application) { Application.initializer({ name: "activeModelAdapter", initialize: function(container, application) { var proxy = new ContainerProxy(container); proxy.registerDeprecations([ {deprecated: 'serializer:_ams', valid: 'serializer:-active-model'}, {deprecated: 'adapter:_ams', valid: 'adapter:-active-model'} ]); application.register('serializer:-active-model', ActiveModelSerializer); application.register('adapter:-active-model', ActiveModelAdapter); } }); }); }); define("activemodel-adapter/lib/main", ["./system","./initializers","exports"], function(__dependency1__, __dependency2__, __exports__) { "use strict"; var ActiveModelAdapter = __dependency1__.ActiveModelAdapter; var ActiveModelSerializer = __dependency1__.ActiveModelSerializer; var EmbeddedRecordsMixin = __dependency1__.EmbeddedRecordsMixin; __exports__.ActiveModelAdapter = ActiveModelAdapter; __exports__.ActiveModelSerializer = ActiveModelSerializer; __exports__.EmbeddedRecordsMixin = EmbeddedRecordsMixin; }); define("activemodel-adapter/lib/system", ["./system/embedded_records_mixin","./system/active_model_adapter","./system/active_model_serializer","exports"], function(__dependency1__, __dependency2__, __dependency3__, __exports__) { "use strict"; var EmbeddedRecordsMixin = __dependency1__["default"]; var ActiveModelAdapter = __dependency2__["default"]; var ActiveModelSerializer = __dependency3__["default"]; __exports__.EmbeddedRecordsMixin = EmbeddedRecordsMixin; __exports__.ActiveModelAdapter = ActiveModelAdapter; __exports__.ActiveModelSerializer = ActiveModelSerializer; }); define("activemodel-adapter/lib/system/active_model_adapter", ["../../../ember-data/lib/adapters","../../../ember-data/lib/system/adapter","../../../ember-inflector/lib/main","./active_model_serializer","./embedded_records_mixin","exports"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __exports__) { "use strict"; var RESTAdapter = __dependency1__.RESTAdapter; var InvalidError = __dependency2__.InvalidError; var pluralize = __dependency3__.pluralize; var ActiveModelSerializer = __dependency4__["default"]; var EmbeddedRecordsMixin = __dependency5__["default"]; /** @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 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. ### 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": { "first_name": "Barack", "last_name": "Obama", "occupation": "President" } } ``` @class ActiveModelAdapter @constructor @namespace DS @extends DS.Adapter **/ 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 @returns 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 jqXHR @returns 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/lib/system/active_model_serializer", ["../../../ember-inflector/lib/main","../../../ember-data/lib/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; var ActiveModelSerializer = RESTSerializer.extend({ // SERIALIZE /** Converts camelcased attributes to underscored when serializing. @method keyForAttribute @param {String} attribute @returns 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 @returns String */ keyForRelationship: function(key, kind) { key = decamelize(key); 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 relationship */ serializePolymorphicType: function(record, json, relationship) { var key = relationship.key, belongsTo = get(record, key); key = this.keyForAttribute(key); json[key + "_type"] = capitalize(camelize(belongsTo.constructor.typeKey)); }, // EXTRACT /** Extracts the model typeKey from underscored root objects. @method typeForRoot @param {String} root @returns String the model's typeKey */ typeForRoot: function(root) { var camelized = camelize(root); return singularize(camelized); }, /** Add extra step to `DS.RESTSerializer.normalize` so links are normalized. If your payload looks like this ```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 @returns 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} hash */ 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) { var payloadKey, payload; if (this.keyForRelationship) { type.eachRelationship(function(key, relationship) { 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); payload = hash[payloadKey]; } hash[key] = payload; if (key !== payloadKey) { delete hash[payloadKey]; } }, this); } } }); __exports__["default"] = ActiveModelSerializer; }); define("activemodel-adapter/lib/system/embedded_records_mixin", ["../../../ember-inflector/lib/main","exports"], function(__dependency1__, __exports__) { "use strict"; var get = Ember.get; var forEach = Ember.EnumerableUtils.forEach; var pluralize = __dependency1__.pluralize; /** The EmbeddedRecordsMixin allows you to add embedded record support to your serializers. To set up embedded records, you include the mixin into the serializer and then define your embedded relations. ```js App.PostSerializer = DS.ActiveModelSerializer.extend(DS.EmbeddedRecordsMixin, { attrs: { comments: {embedded: 'always'} } }) ``` Currently only `{embedded: 'always'}` records are supported. @class EmbeddedRecordsMixin @namespace DS */ var EmbeddedRecordsMixin = Ember.Mixin.create({ /** Serialize has-may relationship when it is configured as embedded objects. @method serializeHasMany */ serializeHasMany: function(record, json, relationship) { var key = relationship.key, attrs = get(this, 'attrs'), embed = attrs && attrs[key] && attrs[key].embedded === 'always'; if (embed) { json[this.keyForAttribute(key)] = get(record, key).map(function(relation) { var data = relation.serialize(), primaryKey = get(this, 'primaryKey'); data[primaryKey] = get(relation, primaryKey); return data; }, this); } }, /** Extract embedded objects out of the payload for a single object and add them as sideloaded objects instead. @method extractSingle */ extractSingle: function(store, primaryType, payload, recordId, requestType) { var root = this.keyForAttribute(primaryType.typeKey), partial = payload[root]; updatePayloadWithEmbedded(store, this, primaryType, partial, payload); return this._super(store, primaryType, payload, recordId, requestType); }, /** Extract embedded objects out of a standard payload and add them as sideloaded objects instead. @method extractArray */ extractArray: function(store, type, payload) { var root = this.keyForAttribute(type.typeKey), partials = payload[pluralize(root)]; forEach(partials, function(partial) { updatePayloadWithEmbedded(store, this, type, partial, payload); }, this); return this._super(store, type, payload); } }); function updatePayloadWithEmbedded(store, serializer, type, partial, payload) { var attrs = get(serializer, 'attrs'); if (!attrs) { return; } type.eachRelationship(function(key, relationship) { var expandedKey, embeddedTypeKey, attribute, ids, config = attrs[key], serializer = store.serializerFor(relationship.type.typeKey), primaryKey = get(serializer, "primaryKey"); if (relationship.kind !== "hasMany") { return; } if (config && (config.embedded === 'always' || config.embedded === 'load')) { // underscore forces the embedded records to be side loaded. // it is needed when main type === relationship.type embeddedTypeKey = '_' + Ember.String.pluralize(relationship.type.typeKey); expandedKey = this.keyForRelationship(key, relationship.kind); attribute = this.keyForAttribute(key); ids = []; if (!partial[attribute]) { return; } payload[embeddedTypeKey] = payload[embeddedTypeKey] || []; forEach(partial[attribute], function(data) { var embeddedType = store.modelFor(relationship.type.typeKey); updatePayloadWithEmbedded(store, serializer, embeddedType, data, payload); ids.push(data[primaryKey]); payload[embeddedTypeKey].push(data); }); partial[expandedKey] = ids; delete partial[attribute]; } }, serializer); } __exports__["default"] = EmbeddedRecordsMixin; }); define("ember-data/lib/adapters", ["./adapters/fixture_adapter","./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/lib/adapters/fixture_adapter", ["../system/adapter","exports"], function(__dependency1__, __exports__) { "use strict"; /** @module ember-data */ var get = Ember.get, fmt = Ember.String.fmt, indexOf = Ember.EnumerableUtils.indexOf; var counter = 0; var Adapter = __dependency1__["default"]; /** `DS.FixtureAdapter` is an adapter that loads records from memory. Its primarily used for development and testing. You can also use `DS.FixtureAdapter` while working on the API but are 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. Its possible to do 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 */ var FixtureAdapter = 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), fixture; Ember.assert("Unable to find fixtures for model type "+type.toString(), fixtures); if (fixtures) { fixture = Ember.A(fixtures).findProperty('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) { var fixture = this.mockJSON(store, type, record); this.deleteLoadedFixture(type, fixture); 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) { if (get(adapter, 'simulateRemoteResponse')) { // Schedule with setTimeout Ember.run.later(function() { resolve(callback.call(context)); }, get(adapter, 'latency')); } else { // Asynchronous, but at the of the runloop with zero latency Ember.run.schedule('actions', null, function() { resolve(callback.call(context)); }); } }, "DS: FixtureAdapter#simulateRemoteCall"); } }); __exports__["default"] = FixtureAdapter; }); define("ember-data/lib/adapters/rest_adapter", ["../system/adapter","exports"], function(__dependency1__, __exports__) { "use strict"; /** @module ember-data */ var Adapter = __dependency1__["default"]; var get = Ember.get, set = Ember.set; 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": { "title": "I'm Running to Reform the W3C's Tag", "author": "Yehuda Katz" } } ``` ### 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": { "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. An array of headers can be added to the adapter which are passed with every request: ```js DS.RESTAdapter.reopen({ headers: { "API_KEY": "secret key", "ANOTHER_HEADER": "Some header value" } }); ``` @class RESTAdapter @constructor @namespace DS @extends DS.Adapter */ var RESTAdapter = Adapter.extend({ defaultSerializer: '-rest', /** 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. An array of headers can be added to the adapter which are passed with every request: ```javascript DS.RESTAdapter.reopen({ 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 @returns {Promise} promise */ find: function(store, type, id) { return this.ajax(this.buildURL(type.typeKey, id), '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 @returns {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 @returns {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 a JSON array for the unloaded records in a has-many relationship that were originally specified as IDs. 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 @returns {Promise} promise */ findMany: function(store, type, ids) { return this.ajax(this.buildURL(type.typeKey), '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 @returns {Promise} promise */ findHasMany: function(store, record, url) { var host = get(this, 'host'), id = get(record, 'id'), 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 @returns {Promise} promise */ findBelongsTo: function(store, record, url) { var id = get(record, 'id'), 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 @returns {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), "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 @returns {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), "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 @returns {Promise} promise */ deleteRecord: function(store, type, record) { var id = get(record, 'id'); return this.ajax(this.buildURL(type.typeKey, id), "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 @returns {String} url */ buildURL: function(type, id) { var url = [], host = get(this, 'host'), prefix = this.urlPrefix(); if (type) { url.push(this.pathForType(type)); } if (id) { url.push(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'), namespace = get(this, 'namespace'), 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('/'); }, /** 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 DS.RESTAdapter.reopen({ pathForType: function(type) { var decamelized = Ember.String.decamelize(type); return Ember.String.pluralize(decamelized); }; }); ``` @method pathForType @param {String} type @returns {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 @return {Object} jqXHR */ ajaxError: function(jqXHR) { if (jqXHR) { jqXHR.then = null; } return jqXHR; }, /** 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, hash) { var adapter = this; return new Ember.RSVP.Promise(function(resolve, reject) { hash = adapter.ajaxOptions(url, type, hash); hash.success = function(json) { Ember.run(null, resolve, json); }; hash.error = function(jqXHR, textStatus, errorThrown) { Ember.run(null, reject, adapter.ajaxError(jqXHR)); }; 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, hash) { hash = hash || {}; 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); } if (this.headers !== undefined) { var headers = this.headers; hash.beforeSend = function (xhr) { forEach.call(Ember.keys(headers), function(key) { xhr.setRequestHeader(key, headers[key]); }); }; } return hash; } }); __exports__["default"] = RESTAdapter; }); define("ember-data/lib/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.7+canary.b45e23ba' @static */ DS = Ember.Namespace.create({ VERSION: '1.0.0-beta.7+canary.b45e23ba' }); if ('undefined' !== typeof window) { window.DS = DS; } if (Ember.libraries) { Ember.libraries.registerCoreLibrary('Ember Data', DS.VERSION); } } __exports__["default"] = DS; }); define("ember-data/lib/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 */ Ember.Date.parse = function (date) { var timestamp, struct, minutesOffset = 0; // ES5 §15.9.4.2 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/lib/initializers", ["./system/store","./serializers","./adapters","./system/debug/debug_adapter","./system/container_proxy","./transforms"], function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__) { "use strict"; var Store = __dependency1__["default"]; var JSONSerializer = __dependency2__.JSONSerializer; var RESTSerializer = __dependency2__.RESTSerializer; var RESTAdapter = __dependency3__.RESTAdapter; var DebugAdapter = __dependency4