Skip to content

Instantly share code, notes, and snippets.

@kieran
Created October 1, 2013 22:14
Show Gist options
  • Save kieran/6786044 to your computer and use it in GitHub Desktop.
Save kieran/6786044 to your computer and use it in GitHub Desktop.
ember model with rsvp baked in
(function(globals) {
var define, requireModule;
(function() {
var registry = {}, seen = {};
define = function(name, deps, callback) {
registry[name] = { deps: deps, callback: callback };
};
requireModule = function(name) {
if (seen[name]) { return seen[name]; }
seen[name] = {};
var mod = registry[name];
if (!mod) {
throw new Error("Module '" + name + "' not found.");
}
var 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(deps[i]));
}
}
var value = callback.apply(this, reified);
return seen[name] = exports || value;
};
})();
define("rsvp/all",
["rsvp/promise","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
/* global toString */
function all(promises) {
if (Object.prototype.toString.call(promises) !== "[object Array]") {
throw new TypeError('You must pass an array to all.');
}
return new Promise(function(resolve, reject) {
var results = [], remaining = promises.length,
promise;
if (remaining === 0) {
resolve([]);
}
function resolver(index) {
return function(value) {
resolveAll(index, value);
};
}
function resolveAll(index, value) {
results[index] = value;
if (--remaining === 0) {
resolve(results);
}
}
for (var i = 0; i < promises.length; i++) {
promise = promises[i];
if (promise && typeof promise.then === 'function') {
promise.then(resolver(i), reject);
} else {
resolveAll(i, promise);
}
}
});
}
__exports__.all = all;
});
define("rsvp/async",
["exports"],
function(__exports__) {
"use strict";
var browserGlobal = (typeof window !== 'undefined') ? window : {};
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
var local = (typeof global !== 'undefined') ? global : this;
// node
function useNextTick() {
return function() {
process.nextTick(flush);
};
}
function useMutationObserver() {
var observer = new BrowserMutationObserver(flush);
var element = document.createElement('div');
observer.observe(element, { attributes: true });
// Chrome Memory Leak: https://bugs.webkit.org/show_bug.cgi?id=93661
window.addEventListener('unload', function(){
observer.disconnect();
observer = null;
}, false);
return function() {
element.setAttribute('drainQueue', 'drainQueue');
};
}
function useSetTimeout() {
return function() {
local.setTimeout(flush, 1);
};
}
var queue = [];
function flush() {
for (var i = 0; i < queue.length; i++) {
var tuple = queue[i];
var callback = tuple[0], arg = tuple[1];
callback(arg);
}
queue = [];
}
var scheduleFlush;
// Decide what async method to use to triggering processing of queued callbacks:
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
scheduleFlush = useNextTick();
} else if (BrowserMutationObserver) {
scheduleFlush = useMutationObserver();
} else {
scheduleFlush = useSetTimeout();
}
function async(callback, arg) {
var length = queue.push([callback, arg]);
if (length === 1) {
// If length is 1, that means that we need to schedule an async flush.
// If additional callbacks are queued before the queue is flushed, they
// will be processed by this flush that we are scheduling.
scheduleFlush();
}
}
__exports__.async = async;
});
define("rsvp/config",
["rsvp/async","exports"],
function(__dependency1__, __exports__) {
"use strict";
var async = __dependency1__.async;
var config = {};
config.async = async;
__exports__.config = config;
});
define("rsvp/defer",
["rsvp/promise","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
function defer() {
var deferred = {
// pre-allocate shape
resolve: undefined,
reject: undefined,
promise: undefined
};
deferred.promise = new Promise(function(resolve, reject) {
deferred.resolve = resolve;
deferred.reject = reject;
});
return deferred;
}
__exports__.defer = defer;
});
define("rsvp/events",
["exports"],
function(__exports__) {
"use strict";
var Event = function(type, options) {
this.type = type;
for (var option in options) {
if (!options.hasOwnProperty(option)) { continue; }
this[option] = options[option];
}
};
var indexOf = function(callbacks, callback) {
for (var i=0, l=callbacks.length; i<l; i++) {
if (callbacks[i][0] === callback) { return i; }
}
return -1;
};
var callbacksFor = function(object) {
var callbacks = object._promiseCallbacks;
if (!callbacks) {
callbacks = object._promiseCallbacks = {};
}
return callbacks;
};
var EventTarget = {
mixin: function(object) {
object.on = this.on;
object.off = this.off;
object.trigger = this.trigger;
return object;
},
on: function(eventNames, callback, binding) {
var allCallbacks = callbacksFor(this), callbacks, eventName;
eventNames = eventNames.split(/\s+/);
binding = binding || this;
while (eventName = eventNames.shift()) {
callbacks = allCallbacks[eventName];
if (!callbacks) {
callbacks = allCallbacks[eventName] = [];
}
if (indexOf(callbacks, callback) === -1) {
callbacks.push([callback, binding]);
}
}
},
off: function(eventNames, callback) {
var allCallbacks = callbacksFor(this), callbacks, eventName, index;
eventNames = eventNames.split(/\s+/);
while (eventName = eventNames.shift()) {
if (!callback) {
allCallbacks[eventName] = [];
continue;
}
callbacks = allCallbacks[eventName];
index = indexOf(callbacks, callback);
if (index !== -1) { callbacks.splice(index, 1); }
}
},
trigger: function(eventName, options) {
var allCallbacks = callbacksFor(this),
callbacks, callbackTuple, callback, binding, event;
if (callbacks = allCallbacks[eventName]) {
// Don't cache the callbacks.length since it may grow
for (var i=0; i<callbacks.length; i++) {
callbackTuple = callbacks[i];
callback = callbackTuple[0];
binding = callbackTuple[1];
if (typeof options !== 'object') {
options = { detail: options };
}
event = new Event(eventName, options);
callback.call(binding, event);
}
}
}
};
__exports__.EventTarget = EventTarget;
});
define("rsvp/hash",
["rsvp/defer","exports"],
function(__dependency1__, __exports__) {
"use strict";
var defer = __dependency1__.defer;
function size(object) {
var s = 0;
for (var prop in object) {
s++;
}
return s;
}
function hash(promises) {
var results = {}, deferred = defer(), remaining = size(promises);
if (remaining === 0) {
deferred.resolve({});
}
var resolver = function(prop) {
return function(value) {
resolveAll(prop, value);
};
};
var resolveAll = function(prop, value) {
results[prop] = value;
if (--remaining === 0) {
deferred.resolve(results);
}
};
var rejectAll = function(error) {
deferred.reject(error);
};
for (var prop in promises) {
if (promises[prop] && typeof promises[prop].then === 'function') {
promises[prop].then(resolver(prop), rejectAll);
} else {
resolveAll(prop, promises[prop]);
}
}
return deferred.promise;
}
__exports__.hash = hash;
});
define("rsvp/node",
["rsvp/promise","rsvp/all","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
var all = __dependency2__.all;
function makeNodeCallbackFor(resolve, reject) {
return function (error, value) {
if (error) {
reject(error);
} else if (arguments.length > 2) {
resolve(Array.prototype.slice.call(arguments, 1));
} else {
resolve(value);
}
};
}
function denodeify(nodeFunc) {
return function() {
var nodeArgs = Array.prototype.slice.call(arguments), resolve, reject;
var thisArg = this;
var promise = new Promise(function(nodeResolve, nodeReject) {
resolve = nodeResolve;
reject = nodeReject;
});
all(nodeArgs).then(function(nodeArgs) {
nodeArgs.push(makeNodeCallbackFor(resolve, reject));
try {
nodeFunc.apply(thisArg, nodeArgs);
} catch(e) {
reject(e);
}
});
return promise;
};
}
__exports__.denodeify = denodeify;
});
define("rsvp/promise",
["rsvp/config","rsvp/events","exports"],
function(__dependency1__, __dependency2__, __exports__) {
"use strict";
var config = __dependency1__.config;
var EventTarget = __dependency2__.EventTarget;
function objectOrFunction(x) {
return isFunction(x) || (typeof x === "object" && x !== null);
}
function isFunction(x){
return typeof x === "function";
}
var Promise = function(resolver) {
var promise = this,
resolved = false;
if (typeof resolver !== 'function') {
throw new TypeError('You must pass a resolver function as the sole argument to the promise constructor');
}
if (!(promise instanceof Promise)) {
return new Promise(resolver);
}
var resolvePromise = function(value) {
if (resolved) { return; }
resolved = true;
resolve(promise, value);
};
var rejectPromise = function(value) {
if (resolved) { return; }
resolved = true;
reject(promise, value);
};
this.on('promise:failed', function(event) {
this.trigger('error', { detail: event.detail });
}, this);
this.on('error', onerror);
try {
resolver(resolvePromise, rejectPromise);
} catch(e) {
rejectPromise(e);
}
};
function onerror(event) {
if (config.onerror) {
config.onerror(event.detail);
}
}
var invokeCallback = function(type, promise, callback, event) {
var hasCallback = isFunction(callback),
value, error, succeeded, failed;
if (hasCallback) {
try {
value = callback(event.detail);
succeeded = true;
} catch(e) {
failed = true;
error = e;
}
} else {
value = event.detail;
succeeded = true;
}
if (handleThenable(promise, value)) {
return;
} else if (hasCallback && succeeded) {
resolve(promise, value);
} else if (failed) {
reject(promise, error);
} else if (type === 'resolve') {
resolve(promise, value);
} else if (type === 'reject') {
reject(promise, value);
}
};
Promise.prototype = {
constructor: Promise,
isRejected: undefined,
isFulfilled: undefined,
rejectedReason: undefined,
fulfillmentValue: undefined,
then: function(done, fail) {
this.off('error', onerror);
var thenPromise = new this.constructor(function() {});
if (this.isFulfilled) {
config.async(function(promise) {
invokeCallback('resolve', thenPromise, done, { detail: promise.fulfillmentValue });
}, this);
}
if (this.isRejected) {
config.async(function(promise) {
invokeCallback('reject', thenPromise, fail, { detail: promise.rejectedReason });
}, this);
}
this.on('promise:resolved', function(event) {
invokeCallback('resolve', thenPromise, done, event);
});
this.on('promise:failed', function(event) {
invokeCallback('reject', thenPromise, fail, event);
});
return thenPromise;
},
fail: function(fail) {
return this.then(null, fail);
}
};
EventTarget.mixin(Promise.prototype);
function resolve(promise, value) {
if (promise === value) {
fulfill(promise, value);
} else if (!handleThenable(promise, value)) {
fulfill(promise, value);
}
}
function handleThenable(promise, value) {
var then = null,
resolved;
try {
if (promise === value) {
throw new TypeError("A promises callback cannot return that same promise.");
}
if (objectOrFunction(value)) {
then = value.then;
if (isFunction(then)) {
then.call(value, function(val) {
if (resolved) { return true; }
resolved = true;
if (value !== val) {
resolve(promise, val);
} else {
fulfill(promise, val);
}
}, function(val) {
if (resolved) { return true; }
resolved = true;
reject(promise, val);
});
return true;
}
}
} catch (error) {
reject(promise, error);
return true;
}
return false;
}
function fulfill(promise, value) {
config.async(function() {
promise.trigger('promise:resolved', { detail: value });
promise.isFulfilled = true;
promise.fulfillmentValue = value;
});
}
function reject(promise, value) {
config.async(function() {
promise.trigger('promise:failed', { detail: value });
promise.isRejected = true;
promise.rejectedReason = value;
});
}
__exports__.Promise = Promise;
});
define("rsvp/reject",
["rsvp/promise","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
function reject(reason) {
return new Promise(function (resolve, reject) {
reject(reason);
});
}
__exports__.reject = reject;
});
define("rsvp/resolve",
["rsvp/promise","exports"],
function(__dependency1__, __exports__) {
"use strict";
var Promise = __dependency1__.Promise;
function resolve(thenable) {
return new Promise(function(resolve, reject) {
resolve(thenable);
});
}
__exports__.resolve = resolve;
});
define("rsvp/rethrow",
["exports"],
function(__exports__) {
"use strict";
var local = (typeof global === "undefined") ? this : global;
function rethrow(reason) {
local.setTimeout(function() {
throw reason;
});
throw reason;
}
__exports__.rethrow = rethrow;
});
define("rsvp",
["rsvp/events","rsvp/promise","rsvp/node","rsvp/all","rsvp/hash","rsvp/rethrow","rsvp/defer","rsvp/config","rsvp/resolve","rsvp/reject","exports"],
function(__dependency1__, __dependency2__, __dependency3__, __dependency4__, __dependency5__, __dependency6__, __dependency7__, __dependency8__, __dependency9__, __dependency10__, __exports__) {
"use strict";
var EventTarget = __dependency1__.EventTarget;
var Promise = __dependency2__.Promise;
var denodeify = __dependency3__.denodeify;
var all = __dependency4__.all;
var hash = __dependency5__.hash;
var rethrow = __dependency6__.rethrow;
var defer = __dependency7__.defer;
var config = __dependency8__.config;
var resolve = __dependency9__.resolve;
var reject = __dependency10__.reject;
function configure(name, value) {
config[name] = value;
}
__exports__.Promise = Promise;
__exports__.EventTarget = EventTarget;
__exports__.all = all;
__exports__.hash = hash;
__exports__.rethrow = rethrow;
__exports__.defer = defer;
__exports__.denodeify = denodeify;
__exports__.configure = configure;
__exports__.resolve = resolve;
__exports__.reject = reject;
});
window.NewRSVP = requireModule("rsvp");
})(window);
(function() {
var VERSION = '0.0.10';
if (Ember.libraries) {
Ember.libraries.register('Ember Model', VERSION);
}
})();
(function() {
function mustImplement(message) {
var fn = function() {
var className = this.constructor.toString();
throw new Error(message.replace('{{className}}', className));
};
fn.isUnimplemented = true;
return fn;
}
Ember.Adapter = Ember.Object.extend({
find: mustImplement('{{className}} must implement find'),
findQuery: mustImplement('{{className}} must implement findQuery'),
findMany: mustImplement('{{className}} must implement findMany'),
findAll: mustImplement('{{className}} must implement findAll'),
createRecord: mustImplement('{{className}} must implement createRecord'),
saveRecord: mustImplement('{{className}} must implement saveRecord'),
deleteRecord: mustImplement('{{className}} must implement deleteRecord'),
load: function(record, id, data) {
record.load(id, data);
}
});
})();
(function() {
var get = Ember.get;
Ember.FixtureAdapter = Ember.Adapter.extend({
_findData: function(klass, id) {
var fixtures = klass.FIXTURES,
idAsString = id.toString(),
primaryKey = get(klass, 'primaryKey'),
data = Ember.A(fixtures).find(function(el) { return (el[primaryKey]).toString() === idAsString; });
return data;
},
find: function(record, id) {
var data = this._findData(record.constructor, id);
return new NewRSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
Ember.run(record, record.load, id, data);
resolve(record);
}, 0);
});
},
findMany: function(klass, records, ids) {
var fixtures = klass.FIXTURES,
requestedData = [];
for (var i = 0, l = ids.length; i < l; i++) {
requestedData.push(this._findData(klass, ids[i]));
}
return new NewRSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
Ember.run(records, records.load, klass, requestedData);
resolve(records);
}, 0);
});
},
findAll: function(klass, records) {
var fixtures = klass.FIXTURES;
return new NewRSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
Ember.run(records, records.load, klass, fixtures);
resolve(records);
}, 0);
});
},
createRecord: function(record) {
var klass = record.constructor,
fixtures = klass.FIXTURES;
return new NewRSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
fixtures.push(klass.findFromCacheOrLoad(record.toJSON()));
record.didCreateRecord();
resolve(record);
}, 0);
});
},
saveRecord: function(record) {
return new NewRSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
record.didSaveRecord();
resolve(record);
}, 0);
});
},
deleteRecord: function(record) {
return new NewRSVP.Promise(function(resolve, reject) {
Ember.run.later(this, function() {
record.didDeleteRecord();
resolve(record);
}, 0);
});
}
});
})();
(function() {
var get = Ember.get,
set = Ember.set;
Ember.RecordArray = Ember.ArrayProxy.extend(Ember.Evented, {
isLoaded: false,
isLoading: Ember.computed.not('isLoaded'),
load: function(klass, data) {
set(this, 'content', this.materializeData(klass, data));
this.notifyLoaded();
},
loadForFindMany: function(klass) {
var content = get(this, '_ids').map(function(id) { return klass.cachedRecordForId(id); });
set(this, 'content', Ember.A(content));
this.notifyLoaded();
},
notifyLoaded: function() {
set(this, 'isLoaded', true);
this.trigger('didLoad');
},
materializeData: function(klass, data) {
return Ember.A(data.map(function(el) {
return klass.findFromCacheOrLoad(el); // FIXME
}));
},
reload: function() {
var modelClass = this.get('modelClass'),
self = this,
promises;
set(this, 'isLoaded', false);
if (modelClass._findAllRecordArray === this) {
modelClass.adapter.findAll(modelClass, this);
} else if (this._query) {
modelClass.adapter.findQuery(modelClass, this, this._query);
} else {
promises = this.map(function(record) {
return record.reload();
});
NewRSVP.all(promises).then(function(data) {
self.notifyLoaded();
});
}
}
});
})();
(function() {
var get = Ember.get;
Ember.FilteredRecordArray = Ember.RecordArray.extend({
init: function() {
if (!get(this, 'modelClass')) {
throw new Error('FilteredRecordArrays must be created with a modelClass');
}
if (!get(this, 'filterFunction')) {
throw new Error('FilteredRecordArrays must be created with a filterFunction');
}
if (!get(this, 'filterProperties')) {
throw new Error('FilteredRecordArrays must be created with filterProperties');
}
var modelClass = get(this, 'modelClass');
modelClass.registerRecordArray(this);
this.registerObservers();
this.updateFilter();
this._super();
},
updateFilter: function() {
var self = this,
results = [];
get(this, 'modelClass').forEachCachedRecord(function(record) {
if (self.filterFunction(record)) {
results.push(record);
}
});
this.set('content', Ember.A(results));
},
updateFilterForRecord: function(record) {
var results = get(this, 'content');
if (this.filterFunction(record) && !results.contains(record)) {
results.pushObject(record);
}
},
registerObservers: function() {
var self = this;
get(this, 'modelClass').forEachCachedRecord(function(record) {
self.registerObserversOnRecord(record);
});
},
registerObserversOnRecord: function(record) {
var self = this,
filterProperties = get(this, 'filterProperties');
for (var i = 0, l = get(filterProperties, 'length'); i < l; i++) {
record.addObserver(filterProperties[i], self, 'updateFilterForRecord');
}
}
});
})();
(function() {
var get = Ember.get, set = Ember.set;
Ember.ManyArray = Ember.RecordArray.extend({
_records: null,
originalContent: null,
isDirty: function() {
var originalContent = get(this, 'originalContent'),
originalContentLength = get(originalContent, 'length'),
content = get(this, 'content'),
contentLength = get(content, 'length');
if (originalContentLength !== contentLength) { return true; }
var isDirty = false;
for (var i = 0, l = contentLength; i < l; i++) {
if (!originalContent.contains(content[i])) {
isDirty = true;
break;
}
}
return isDirty;
}.property('content.[]', 'originalContent'),
objectAtContent: function(idx) {
var content = get(this, 'content');
if (!content.length) { return; }
return this.materializeRecord(idx);
},
save: function() {
// TODO: loop over dirty records only
return NewRSVP.all(this.map(function(record) {
return record.save();
}));
},
replaceContent: function(index, removed, added) {
added = Ember.EnumerableUtils.map(added, function(record) {
return record._reference;
}, this);
this._super(index, removed, added);
},
_contentWillChange: function() {
var content = get(this, 'content');
if (content) {
content.removeArrayObserver(this);
this._setupOriginalContent(content);
}
}.observesBefore('content'),
_contentDidChange: function() {
var content = get(this, 'content');
if (content) {
content.addArrayObserver(this);
this.arrayDidChange(content, 0, 0, get(content, 'length'));
}
}.observes('content'),
arrayWillChange: function(item, idx, removedCnt, addedCnt) {},
arrayDidChange: function(item, idx, removedCnt, addedCnt) {
var parent = get(this, 'parent'), relationshipKey = get(this, 'relationshipKey'),
isDirty = get(this, 'isDirty');
if (isDirty) {
parent._relationshipBecameDirty(relationshipKey);
} else {
parent._relationshipBecameClean(relationshipKey);
}
},
_setupOriginalContent: function(content) {
content = content || get(this, 'content');
if (content) {
set(this, 'originalContent', content.slice());
}
},
init: function() {
this._super();
this._setupOriginalContent();
this._contentDidChange();
}
});
Ember.HasManyArray = Ember.ManyArray.extend({
materializeRecord: function(idx) {
var klass = get(this, 'modelClass'),
content = get(this, 'content'),
reference = content.objectAt(idx),
record;
if (reference.record) {
record = reference.record;
} else {
record = klass.find(reference.id);
}
return record;
},
toJSON: function() {
var ids = [], content = this.get('content');
content.forEach(function(reference) {
if (reference.id) {
ids.push(reference.id);
}
});
return ids;
}
});
Ember.EmbeddedHasManyArray = Ember.ManyArray.extend({
create: function(attrs) {
var klass = get(this, 'modelClass'),
record = klass.create(attrs);
this.pushObject(record);
return record; // FIXME: inject parent's id
},
materializeRecord: function(idx) {
var klass = get(this, 'modelClass'),
primaryKey = get(klass, 'primaryKey'),
content = get(this, 'content'),
reference = content.objectAt(idx),
attrs = reference.data;
if (reference.record) {
return reference.record;
} else {
var record = klass.create({ _reference: reference });
reference.record = record;
if (attrs) {
record.load(attrs[primaryKey], attrs);
}
return record;
}
},
toJSON: function() {
return this.map(function(record) {
return record.toJSON();
});
}
});
})();
(function() {
var get = Ember.get,
set = Ember.set,
setProperties = Ember.setProperties,
meta = Ember.meta,
underscore = Ember.String.underscore;
function contains(array, element) {
for (var i = 0, l = array.length; i < l; i++) {
if (array[i] === element) { return true; }
}
return false;
}
function concatUnique(toArray, fromArray) {
var e;
for (var i = 0, l = fromArray.length; i < l; i++) {
e = fromArray[i];
if (!contains(toArray, e)) { toArray.push(e); }
}
return toArray;
}
function hasCachedValue(object, key) {
var objectMeta = meta(object, false);
if (objectMeta) {
return key in objectMeta.cache;
}
}
Ember.run.queues.push('data');
Ember.Model = Ember.Object.extend(Ember.Evented, {
isLoaded: true,
isLoading: Ember.computed.not('isLoaded'),
isNew: true,
isDeleted: false,
_dirtyAttributes: null,
/**
Called when attribute is accessed.
@method getAttr
@param key {String} key which is being accessed
@param value {Object} value, which will be returned from getter by default
*/
getAttr: function(key, value) {
return value;
},
isDirty: function() {
var dirtyAttributes = get(this, '_dirtyAttributes');
return dirtyAttributes && dirtyAttributes.length !== 0 || false;
}.property('_dirtyAttributes.length'),
_relationshipBecameDirty: function(name) {
var dirtyAttributes = get(this, '_dirtyAttributes');
if (!dirtyAttributes.contains(name)) { dirtyAttributes.pushObject(name); }
},
_relationshipBecameClean: function(name) {
var dirtyAttributes = get(this, '_dirtyAttributes');
dirtyAttributes.removeObject(name);
},
dataKey: function(key) {
var camelizeKeys = get(this.constructor, 'camelizeKeys');
var meta = this.constructor.metaForProperty(key);
if (meta.options && meta.options.key) {
return camelizeKeys ? underscore(meta.options.key) : meta.options.key;
}
return camelizeKeys ? underscore(key) : key;
},
init: function() {
this._createReference();
if (!this._dirtyAttributes) {
set(this, '_dirtyAttributes', []);
}
this._super();
},
_createReference: function() {
var reference = this._reference,
id = this.getPrimaryKey();
if (!reference) {
reference = this.constructor._getOrCreateReferenceForId(id);
reference.record = this;
this._reference = reference;
} else if (reference.id !== id) {
reference.id = id;
this.constructor._cacheReference(reference);
}
if (!reference.id) {
reference.id = id;
}
return reference;
},
getPrimaryKey: function() {
return get(this, get(this.constructor, 'primaryKey'));
},
load: function(id, hash) {
var data = {};
data[get(this.constructor, 'primaryKey')] = id;
set(this, '_data', Ember.merge(data, hash));
// eagerly load embedded data
var relationships = this.constructor._relationships || [], meta = Ember.meta(this), relationshipKey, relationship, relationshipMeta, relationshipData, relationshipType;
for (var i = 0, l = relationships.length; i < l; i++) {
relationshipKey = relationships[i];
relationship = meta.descs[relationshipKey];
relationshipMeta = relationship.meta();
if (relationshipMeta.options.embedded) {
relationshipType = relationshipMeta.type;
if (typeof relationshipType === "string") {
relationshipType = Ember.get(Ember.lookup, relationshipType);
}
relationshipData = data[relationshipKey];
if (relationshipData) {
relationshipType.load(relationshipData);
}
}
}
set(this, 'isLoaded', true);
set(this, 'isNew', false);
this._createReference();
this.trigger('didLoad');
},
didDefineProperty: function(proto, key, value) {
if (value instanceof Ember.Descriptor) {
var meta = value.meta();
var klass = proto.constructor;
if (meta.isAttribute) {
if (!klass._attributes) { klass._attributes = []; }
klass._attributes.push(key);
} else if (meta.isRelationship) {
if (!klass._relationships) { klass._relationships = []; }
klass._relationships.push(key);
meta.relationshipKey = key;
}
}
},
serializeHasMany: function(key, meta) {
return this.get(key).toJSON();
},
serializeBelongsTo: function(key, meta) {
if (meta.options.embedded) {
var record = this.get(key);
return record ? record.toJSON() : null;
} else {
var primaryKey = get(meta.getType(), 'primaryKey');
return this.get(key + '.' + primaryKey);
}
},
toJSON: function() {
var key, meta,
json = {},
attributes = this.constructor.getAttributes(),
relationships = this.constructor.getRelationships(),
properties = attributes ? this.getProperties(attributes) : {},
rootKey = get(this.constructor, 'rootKey');
for (key in properties) {
meta = this.constructor.metaForProperty(key);
if (meta.type && meta.type.serialize) {
json[this.dataKey(key)] = meta.type.serialize(properties[key]);
} else if (meta.type && Ember.Model.dataTypes[meta.type]) {
json[this.dataKey(key)] = Ember.Model.dataTypes[meta.type].serialize(properties[key]);
} else {
json[this.dataKey(key)] = properties[key];
}
}
if (relationships) {
var data, relationshipKey;
for(var i = 0; i < relationships.length; i++) {
key = relationships[i];
meta = this.constructor.metaForProperty(key);
relationshipKey = meta.options.key || key;
if (meta.kind === 'belongsTo') {
data = this.serializeBelongsTo(key, meta);
} else {
data = this.serializeHasMany(key, meta);
}
json[relationshipKey] = data;
}
}
if (rootKey) {
var jsonRoot = {};
jsonRoot[rootKey] = json;
return jsonRoot;
} else {
return json;
}
},
save: function() {
var adapter = this.constructor.adapter;
set(this, 'isSaving', true);
if (get(this, 'isNew')) {
return adapter.createRecord(this);
} else if (get(this, 'isDirty')) {
return adapter.saveRecord(this);
} else { // noop, return a resolved promise
var self = this,
promise = new NewRSVP.Promise(function(resolve, reject) {
resolve(self);
});
set(this, 'isSaving', false);
return promise;
}
},
reload: function() {
return this.constructor.reload(this.get(get(this.constructor, 'primaryKey')));
},
revert: function() {
this.getWithDefault('_dirtyAttributes', []).clear();
this.notifyPropertyChange('_data');
},
didCreateRecord: function() {
var primaryKey = get(this.constructor, 'primaryKey'),
id = get(this, primaryKey);
set(this, 'isNew', false);
set(this, '_dirtyAttributes', []);
this.constructor.addToRecordArrays(this);
this.trigger('didCreateRecord');
this.didSaveRecord();
},
didSaveRecord: function() {
set(this, 'isSaving', false);
this.trigger('didSaveRecord');
if (this.get('isDirty')) { this._copyDirtyAttributesToData(); }
},
deleteRecord: function() {
return this.constructor.adapter.deleteRecord(this);
},
didDeleteRecord: function() {
this.constructor.removeFromRecordArrays(this);
set(this, 'isDeleted', true);
this.trigger('didDeleteRecord');
},
_copyDirtyAttributesToData: function() {
if (!this._dirtyAttributes) { return; }
var dirtyAttributes = this._dirtyAttributes,
data = get(this, '_data'),
key;
if (!data) {
data = {};
set(this, '_data', data);
}
for (var i = 0, l = dirtyAttributes.length; i < l; i++) {
// TODO: merge Object.create'd object into prototype
key = dirtyAttributes[i];
data[this.dataKey(key)] = this.cacheFor(key);
}
set(this, '_dirtyAttributes', []);
},
dataDidChange: Ember.observer(function() {
this._reloadHasManys();
}, '_data'),
_registerHasManyArray: function(array) {
if (!this._hasManyArrays) { this._hasManyArrays = Ember.A([]); }
this._hasManyArrays.pushObject(array);
},
_reloadHasManys: function() {
if (!this._hasManyArrays) { return; }
var i, j;
for (i = 0; i < this._hasManyArrays.length; i++) {
var array = this._hasManyArrays[i],
hasManyContent = this._getHasManyContent(get(array, 'key'), get(array, 'modelClass'), get(array, 'embedded'));
for (j = 0; j < array.get('length'); j++) {
if (array.objectAt(j).get('isNew')) {
hasManyContent.addObject(array.objectAt(j)._reference);
}
}
set(array, 'content', hasManyContent);
}
},
_getHasManyContent: function(key, type, embedded) {
var content = get(this, '_data.' + key);
if (content) {
var mapFunction, primaryKey, reference;
if (embedded) {
primaryKey = get(type, 'primaryKey');
mapFunction = function(attrs) {
reference = type._getOrCreateReferenceForId(attrs[primaryKey]);
reference.data = attrs;
return reference;
};
} else {
mapFunction = function(id) { return type._getOrCreateReferenceForId(id); };
}
content = Ember.EnumerableUtils.map(content, mapFunction);
}
return Ember.A(content || []);
}
});
Ember.Model.reopenClass({
primaryKey: 'id',
adapter: Ember.Adapter.create(),
_clientIdCounter: 1,
getAttributes: function() {
this.proto(); // force class "compilation" if it hasn't been done.
var attributes = this._attributes || [];
if (typeof this.superclass.getAttributes === 'function') {
attributes = this.superclass.getAttributes().concat(attributes);
}
return attributes;
},
getRelationships: function() {
this.proto(); // force class "compilation" if it hasn't been done.
var relationships = this._relationships || [];
if (typeof this.superclass.getRelationships === 'function') {
relationships = this.superclass.getRelationships().concat(relationships);
}
return relationships;
},
fetch: function(id) {
if (!arguments.length) {
return this._findFetchAll(true);
} else if (Ember.isArray(id)) {
return this._findFetchMany(id, true);
} else if (typeof id === 'object') {
return this._findFetchQuery(id, true);
} else {
return this._findFetchById(id, true);
}
},
find: function(id) {
if (!arguments.length) {
return this._findFetchAll(false);
} else if (Ember.isArray(id)) {
return this._findFetchMany(id, false);
} else if (typeof id === 'object') {
return this._findFetchQuery(id, false);
} else {
return this._findFetchById(id, false);
}
},
findQuery: function(params) {
return this._findFetchQuery(params, false);
},
fetchQuery: function(params) {
return this._findFetchQuery(params, true);
},
_findFetchQuery: function(params, isFetch) {
var records = Ember.RecordArray.create({modelClass: this, _query: params});
var promise = this.adapter.findQuery(this, records, params);
return isFetch ? promise : records;
},
findMany: function(ids) {
return this._findFetchMany(ids, false);
},
fetchMany: function(ids) {
return this._findFetchMany(ids, true);
},
_findFetchMany: function(ids, isFetch) {
Ember.assert("findFetchMany requires an array", Ember.isArray(ids));
var records = Ember.RecordArray.create({_ids: ids, modelClass: this}),
deferred;
if (!this.recordArrays) { this.recordArrays = []; }
this.recordArrays.push(records);
if (this._currentBatchIds) {
concatUnique(this._currentBatchIds, ids);
this._currentBatchRecordArrays.push(records);
} else {
this._currentBatchIds = concatUnique([], ids);
this._currentBatchRecordArrays = [records];
}
if (isFetch) {
deferred = Ember.Deferred.create();
Ember.set(deferred, 'resolveWith', records);
if (!this._currentBatchDeferreds) { this._currentBatchDeferreds = []; }
this._currentBatchDeferreds.push(deferred);
}
Ember.run.scheduleOnce('data', this, this._executeBatch);
return isFetch ? deferred : records;
},
findAll: function() {
return this._findFetchAll(false);
},
fetchAll: function() {
return this._findFetchAll(true);
},
_findFetchAll: function(isFetch) {
var self = this;
if (this._findAllRecordArray) {
if (isFetch) {
return new NewRSVP.Promise(function(resolve) {
resolve(self._findAllRecordArray);
});
} else {
return this._findAllRecordArray;
}
}
var records = this._findAllRecordArray = Ember.RecordArray.create({modelClass: this});
var promise = this.adapter.findAll(this, records);
// Remove the cached record array if the promise is rejected
if (promise.then) {
promise.then(null, function() {
self._findAllRecordArray = null;
return NewRSVP.reject.apply(null, arguments);
});
}
return isFetch ? promise : records;
},
findById: function(id) {
return this._findFetchById(id, false);
},
fetchById: function(id) {
return this._findFetchById(id, true);
},
_findFetchById: function(id, isFetch) {
var record = this.cachedRecordForId(id),
isLoaded = get(record, 'isLoaded'),
adapter = get(this, 'adapter'),
deferredOrPromise;
if (isLoaded) {
if (isFetch) {
return new NewRSVP.Promise(function(resolve, reject) {
resolve(record);
});
} else {
return record;
}
}
deferredOrPromise = this._fetchById(record, id);
return isFetch ? deferredOrPromise : record;
},
_currentBatchIds: null,
_currentBatchRecordArrays: null,
_currentBatchDeferreds: null,
reload: function(id) {
var record = this.cachedRecordForId(id);
record.set('isLoaded', false);
return this._fetchById(record, id);
},
_fetchById: function(record, id) {
var adapter = get(this, 'adapter'),
deferred;
if (adapter.findMany && !adapter.findMany.isUnimplemented) {
if (this._currentBatchIds) {
if (!contains(this._currentBatchIds, id)) { this._currentBatchIds.push(id); }
} else {
this._currentBatchIds = [id];
this._currentBatchRecordArrays = [];
}
deferred = Ember.Deferred.create();
//Attached the record to the deferred so we can resolove it later.
Ember.set(deferred, 'resolveWith', record);
if (!this._currentBatchDeferreds) { this._currentBatchDeferreds = []; }
this._currentBatchDeferreds.push(deferred);
Ember.run.scheduleOnce('data', this, this._executeBatch);
return deferred;
} else {
return adapter.find(record, id);
}
},
_executeBatch: function() {
var batchIds = this._currentBatchIds,
batchRecordArrays = this._currentBatchRecordArrays,
batchDeferreds = this._currentBatchDeferreds,
self = this,
requestIds = [],
promise,
i;
this._currentBatchIds = null;
this._currentBatchRecordArrays = null;
this._currentBatchDeferreds = null;
for (i = 0; i < batchIds.length; i++) {
if (!this.cachedRecordForId(batchIds[i]).get('isLoaded')) {
requestIds.push(batchIds[i]);
}
}
if (batchIds.length === 1) {
promise = get(this, 'adapter').find(this.cachedRecordForId(batchIds[0]), batchIds[0]);
} else {
var recordArray = Ember.RecordArray.create({_ids: batchIds});
if (requestIds.length === 0) {
promise = new NewRSVP.Promise(function(resolve, reject) { resolve(recordArray); });
recordArray.notifyLoaded();
} else {
promise = get(this, 'adapter').findMany(this, recordArray, requestIds);
}
}
promise.then(function() {
for (var i = 0, l = batchRecordArrays.length; i < l; i++) {
batchRecordArrays[i].loadForFindMany(self);
}
if (batchDeferreds) {
for (i = 0, l = batchDeferreds.length; i < l; i++) {
var resolveWith = Ember.get(batchDeferreds[i], 'resolveWith');
batchDeferreds[i].resolve(resolveWith);
}
}
}).then(null, function(errorXHR) {
if (batchDeferreds) {
for (var i = 0, l = batchDeferreds.length; i < l; i++) {
batchDeferreds[i].reject(errorXHR);
}
}
});
},
getCachedReferenceRecord: function(id){
var ref = this._getReferenceById(id);
if(ref) return ref.record;
return undefined;
},
cachedRecordForId: function(id) {
var record = this.getCachedReferenceRecord(id);
if (!record) {
var primaryKey = get(this, 'primaryKey'),
attrs = {isLoaded: false};
attrs[primaryKey] = id;
record = this.create(attrs);
var sideloadedData = this.sideloadedData && this.sideloadedData[id];
if (sideloadedData) {
record.load(id, sideloadedData);
}
}
return record;
},
addToRecordArrays: function(record) {
if (this._findAllRecordArray) {
this._findAllRecordArray.pushObject(record);
}
if (this.recordArrays) {
this.recordArrays.forEach(function(recordArray) {
if (recordArray instanceof Ember.FilteredRecordArray) {
recordArray.registerObserversOnRecord(record);
recordArray.updateFilter();
} else {
recordArray.pushObject(record);
}
});
}
},
unload: function (record) {
this.removeFromRecordArrays(record);
var primaryKey = record.get(get(this, 'primaryKey'));
this.removeFromCache(primaryKey);
},
clearCache: function () {
this.sideloadedData = undefined;
this._referenceCache = undefined;
},
removeFromCache: function (key) {
if (this.sideloadedData && this.sideloadedData[key]) {
delete this.sideloadedData[key];
}
if(this._referenceCache && this._referenceCache[key]) {
delete this._referenceCache[key];
}
},
removeFromRecordArrays: function(record) {
if (this._findAllRecordArray) {
this._findAllRecordArray.removeObject(record);
}
if (this.recordArrays) {
this.recordArrays.forEach(function(recordArray) {
recordArray.removeObject(record);
});
}
},
// FIXME
findFromCacheOrLoad: function(data) {
var record;
if (!data[get(this, 'primaryKey')]) {
record = this.create({isLoaded: false});
} else {
record = this.cachedRecordForId(data[get(this, 'primaryKey')]);
}
// set(record, 'data', data);
record.load(data[get(this, 'primaryKey')], data);
return record;
},
registerRecordArray: function(recordArray) {
if (!this.recordArrays) { this.recordArrays = []; }
this.recordArrays.push(recordArray);
},
unregisterRecordArray: function(recordArray) {
if (!this.recordArrays) { return; }
Ember.A(this.recordArrays).removeObject(recordArray);
},
forEachCachedRecord: function(callback) {
var ids = Object.keys(this._referenceCache);
ids.map(function(id) {
return this._getReferenceById(id).record;
}, this).forEach(callback);
},
load: function(hashes) {
if (Ember.typeOf(hashes) !== 'array') { hashes = [hashes]; }
if (!this.sideloadedData) { this.sideloadedData = {}; }
for (var i = 0, l = hashes.length; i < l; i++) {
var hash = hashes[i],
primaryKey = hash[get(this, 'primaryKey')],
record = this.getCachedReferenceRecord(primaryKey);
if (record) {
record.load(primaryKey, hash);
} else {
this.sideloadedData[primaryKey] = hash;
}
}
},
_getReferenceById: function(id) {
if (!this._referenceCache) { this._referenceCache = {}; }
return this._referenceCache[id];
},
_getOrCreateReferenceForId: function(id) {
var reference = this._getReferenceById(id);
if (!reference) {
reference = this._createReference(id);
}
return reference;
},
_createReference: function(id) {
if (!this._referenceCache) { this._referenceCache = {}; }
Ember.assert('The id ' + id + ' has alread been used with another record of type ' + this.toString() + '.', !id || !this._referenceCache[id]);
var reference = {
id: id,
clientId: this._clientIdCounter++
};
this._cacheReference(reference);
return reference;
},
_cacheReference: function(reference) {
// if we're creating an item, this process will be done
// later, once the object has been persisted.
if (reference.id) {
this._referenceCache[reference.id] = reference;
}
}
});
})();
(function() {
var get = Ember.get;
Ember.hasMany = function(type, options) {
options = options || {};
var meta = { type: type, isRelationship: true, options: options, kind: 'hasMany' },
key = options.key;
return Ember.computed(function() {
if (typeof type === "string") {
type = Ember.get(Ember.lookup, type);
}
return this.getHasMany(key, type, meta);
}).property().meta(meta);
};
Ember.Model.reopen({
getHasMany: function(key, type, meta) {
var embedded = meta.options.embedded,
collectionClass = embedded ? Ember.EmbeddedHasManyArray : Ember.HasManyArray;
var collection = collectionClass.create({
parent: this,
modelClass: type,
content: this._getHasManyContent(key, type, embedded),
embedded: embedded,
key: key,
relationshipKey: meta.relationshipKey
});
this._registerHasManyArray(collection);
return collection;
}
});
})();
(function() {
var get = Ember.get,
set = Ember.set;
function getType() {
if (typeof this.type === "string") {
this.type = Ember.get(Ember.lookup, this.type);
}
return this.type;
}
Ember.belongsTo = function(type, options) {
options = options || {};
var meta = { type: type, isRelationship: true, options: options, kind: 'belongsTo', getType: getType },
relationshipKey = options.key;
return Ember.computed(function(key, value, oldValue) {
type = meta.getType();
var dirtyAttributes = get(this, '_dirtyAttributes'),
createdDirtyAttributes = false;
if (!dirtyAttributes) {
dirtyAttributes = [];
createdDirtyAttributes = true;
}
if (arguments.length > 1) {
if (value) {
Ember.assert(Ember.String.fmt('Attempted to set property of type: %@ with a value of type: %@',
[value.constructor, type]),
value instanceof type);
if (oldValue !== value) {
dirtyAttributes.pushObject(key);
} else {
dirtyAttributes.removeObject(key);
}
if (createdDirtyAttributes) {
set(this, '_dirtyAttributes', dirtyAttributes);
}
}
return value === undefined ? null : value;
} else {
return this.getBelongsTo(relationshipKey, type, meta);
}
}).property('_data').meta(meta);
};
Ember.Model.reopen({
getBelongsTo: function(key, type, meta) {
var idOrAttrs = get(this, '_data.' + key),
record;
if (Ember.isNone(idOrAttrs)) {
return null;
}
if (meta.options.embedded) {
var primaryKey = get(type, 'primaryKey'),
id = idOrAttrs[primaryKey];
record = type.create({ isLoaded: false, id: id });
record.load(id, idOrAttrs);
} else {
record = type.find(idOrAttrs);
}
return record;
}
});
})();
(function() {
var get = Ember.get,
set = Ember.set,
meta = Ember.meta;
Ember.Model.dataTypes = {};
Ember.Model.dataTypes[Date] = {
deserialize: function(string) {
if (!string) { return null; }
return new Date(string);
},
serialize: function (date) {
if (!date) { return null; }
return date.toISOString();
},
isEqual: function(obj1, obj2) {
if (obj1 instanceof Date) { obj1 = this.serialize(obj1); }
if (obj2 instanceof Date) { obj2 = this.serialize(obj2); }
return obj1 === obj2;
}
};
Ember.Model.dataTypes[Number] = {
deserialize: function(string) {
if (!string && string !== 0) { return null; }
return Number(string);
},
serialize: function (number) {
if (!number && number !== 0) { return null; }
return Number(number);
}
};
function deserialize(value, type) {
if (type && type.deserialize) {
return type.deserialize(value);
} else if (type && Ember.Model.dataTypes[type]) {
return Ember.Model.dataTypes[type].deserialize(value);
} else {
return value;
}
}
Ember.attr = function(type, options) {
return Ember.computed(function(key, value) {
var data = get(this, '_data'),
dataKey = this.dataKey(key),
dataValue = data && get(data, dataKey),
beingCreated = meta(this).proto === this,
dirtyAttributes = get(this, '_dirtyAttributes'),
createdDirtyAttributes = false;
if (!dirtyAttributes) {
dirtyAttributes = [];
createdDirtyAttributes = true;
}
if (arguments.length === 2) {
if (beingCreated) {
if (!data) {
data = {};
set(this, '_data', data);
}
dataValue = data[dataKey] = value;
}
if (dataValue !== value) {
dirtyAttributes.pushObject(key);
} else {
dirtyAttributes.removeObject(key);
}
if (createdDirtyAttributes) {
set(this, '_dirtyAttributes', dirtyAttributes);
}
return value;
}
return this.getAttr(key, deserialize(dataValue, type));
}).property('_data').meta({isAttribute: true, type: type, options: options});
};
})();
(function() {
var get = Ember.get;
Ember.RESTAdapter = Ember.Adapter.extend({
find: function(record, id) {
var url = this.buildURL(record.constructor, id),
self = this;
return this.ajax(url).then(function(data) {
self.didFind(record, id, data);
return record;
});
},
didFind: function(record, id, data) {
var rootKey = get(record.constructor, 'rootKey'),
dataToLoad = rootKey ? data[rootKey] : data;
record.load(id, dataToLoad);
},
findAll: function(klass, records) {
var url = this.buildURL(klass),
self = this;
return this.ajax(url).then(function(data) {
self.didFindAll(klass, records, data);
return records;
});
},
didFindAll: function(klass, records, data) {
var collectionKey = get(klass, 'collectionKey'),
dataToLoad = collectionKey ? data[collectionKey] : data;
records.load(klass, dataToLoad);
},
findQuery: function(klass, records, params) {
var url = this.buildURL(klass),
self = this;
return this.ajax(url, params).then(function(data) {
self.didFindQuery(klass, records, params, data);
return records;
});
},
didFindQuery: function(klass, records, params, data) {
var collectionKey = get(klass, 'collectionKey'),
dataToLoad = collectionKey ? data[collectionKey] : data;
records.load(klass, dataToLoad);
},
createRecord: function(record) {
var url = this.buildURL(record.constructor),
self = this;
return this.ajax(url, record.toJSON(), "POST").then(function(data) {
self.didCreateRecord(record, data);
return record;
});
},
didCreateRecord: function(record, data) {
var rootKey = get(record.constructor, 'rootKey'),
primaryKey = get(record.constructor, 'primaryKey'),
dataToLoad = rootKey ? data[rootKey] : data;
record.load(dataToLoad[primaryKey], dataToLoad);
record.didCreateRecord();
},
saveRecord: function(record) {
var primaryKey = get(record.constructor, 'primaryKey'),
url = this.buildURL(record.constructor, get(record, primaryKey)),
self = this;
return this.ajax(url, record.toJSON(), "PUT").then(function(data) { // TODO: Some APIs may or may not return data
self.didSaveRecord(record, data);
return record;
});
},
didSaveRecord: function(record, data) {
record.didSaveRecord();
},
deleteRecord: function(record) {
var primaryKey = get(record.constructor, 'primaryKey'),
url = this.buildURL(record.constructor, get(record, primaryKey)),
self = this;
return this.ajax(url, record.toJSON(), "DELETE").then(function(data) { // TODO: Some APIs may or may not return data
self.didDeleteRecord(record, data);
});
},
didDeleteRecord: function(record, data) {
record.didDeleteRecord();
},
ajax: function(url, params, method) {
return this._ajax(url, params, method || "GET");
},
buildURL: function(klass, id) {
var urlRoot = get(klass, 'url');
if (!urlRoot) { throw new Error('Ember.RESTAdapter requires a `url` property to be specified'); }
if (!Ember.isEmpty(id)) {
return urlRoot + "/" + id + ".json";
} else {
return urlRoot + ".json";
}
},
ajaxSettings: function(url, method) {
return {
url: url,
type: method,
dataType: "json"
};
},
_ajax: function(url, params, method) {
var settings = this.ajaxSettings(url, method);
return new NewRSVP.Promise(function(resolve, reject) {
if (params) {
if (method === "GET") {
settings.data = params;
} else {
settings.contentType = "application/json; charset=utf-8";
settings.data = JSON.stringify(params);
}
}
settings.success = function(json) {
Ember.run(null, resolve, json);
};
settings.error = function(jqXHR, textStatus, errorThrown) {
// https://github.com/ebryn/ember-model/issues/202
if (jqXHR) {
jqXHR.then = null;
}
Ember.run(null, reject, jqXHR);
};
Ember.$.ajax(settings);
});
}
});
})();
(function() {
var get = Ember.get;
Ember.LoadPromise = Ember.Object.extend(Ember.DeferredMixin, {
init: function() {
this._super.apply(this, arguments);
var target = get(this, 'target');
if (get(target, 'isLoaded') && !get(target, 'isNew')) {
this.resolve(target);
} else {
target.one('didLoad', this, function() {
this.resolve(target);
});
}
}
});
Ember.loadPromise = function(target) {
if (Ember.isNone(target)) {
return null;
} else if (target.then) {
return target;
} else {
return Ember.LoadPromise.create({target: target});
}
};
})();
(function() {
// This is a debug adapter for the Ember Extension, don't let the fact this is called an "adapter" confuse you.
// Most copied from: https://github.com/emberjs/data/blob/master/packages/ember-data/lib/system/debug/debug_adapter.js
if (!Ember.DataAdapter) { return; }
var get = Ember.get, capitalize = Ember.String.capitalize, underscore = Ember.String.underscore;
var DebugAdapter = Ember.DataAdapter.extend({
getFilters: function() {
return [
{ name: 'isNew', desc: 'New' },
{ name: 'isModified', desc: 'Modified' },
{ name: 'isClean', desc: 'Clean' }
];
},
detect: function(klass) {
return klass !== Ember.Model && Ember.Model.detect(klass);
},
columnsForType: function(type) {
var columns = [], count = 0, self = this;
Ember.A(get(type.proto(), 'attributes')).forEach(function(name, meta) {
if (count++ > self.attributeLimit) { return false; }
var desc = capitalize(underscore(name).replace('_', ' '));
columns.push({ name: name, desc: desc });
});
return columns;
},
getRecords: function(type) {
var records = [];
type.forEachCachedRecord(function(record) { records.push(record); });
return records;
},
getRecordColumnValues: function(record) {
var self = this, count = 0,
columnValues = { id: get(record, 'id') };
record.get('attributes').forEach(function(key) {
if (count++ > self.attributeLimit) {
return false;
}
var value = get(record, key);
columnValues[key] = value;
});
return columnValues;
},
getRecordKeywords: function(record) {
var keywords = [], keys = Ember.A(['id']);
record.get('attributes').forEach(function(key) {
keys.push(key);
});
keys.forEach(function(key) {
keywords.push(get(record, key));
});
return keywords;
},
getRecordFilterValues: function(record) {
return {
isNew: record.get('isNew'),
isModified: record.get('isDirty') && !record.get('isNew'),
isClean: !record.get('isDirty')
};
},
getRecordColor: function(record) {
var color = 'black';
if (record.get('isNew')) {
color = 'green';
} else if (record.get('isDirty')) {
color = 'blue';
}
return color;
},
observeRecord: function(record, recordUpdated) {
var releaseMethods = Ember.A(), self = this,
keysToObserve = Ember.A(['id', 'isNew', 'isDirty']);
record.get('attributes').forEach(function(key) {
keysToObserve.push(key);
});
keysToObserve.forEach(function(key) {
var handler = function() {
recordUpdated(self.wrapRecord(record));
};
Ember.addObserver(record, key, handler);
releaseMethods.push(function() {
Ember.removeObserver(record, key, handler);
});
});
var release = function() {
releaseMethods.forEach(function(fn) { fn(); } );
};
return release;
}
});
Ember.onLoad('Ember.Application', function(Application) {
Application.initializer({
name: "dataAdapter",
initialize: function(container, application) {
application.register('dataAdapter:main', DebugAdapter);
}
});
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment