Browse files

Version 0.11.0.

  • Loading branch information...
1 parent 8fc16e7 commit 387f06cabb72c06a35b38a4b29026a3f53167e93 @benpickles committed Mar 7, 2012
Showing with 818 additions and 73 deletions.
  1. +24 −19 CHANGELOG.markdown
  2. +1 −1 VERSION
  3. +718 −0 dist/js-model-0.11.0.js
  4. +23 −0 dist/js-model-0.11.0.min.js
  5. +52 −53 index.html
View
43 CHANGELOG.markdown
@@ -1,41 +1,46 @@
# Changelog
-## 0.10.1
+## 0.11.0 - 7/3/12
+
+ * Emit a "change" or "change:ATTRIBUTE_NAME" event when modifying attributes on an instance.
+ * Remove jQuery dependency (REST persistence still requires jQuery).
+
+## 0.10.1 - 7/4/11
* Add a simple plugin interface. Call with `MyModel.use(MyPlugin, "some", "args")`.
* Switch to prototypal inheritance instead of copying functions into a new object.
* `Model.each()`, `.map()` and `.select()` now behave more like their ECMA-262 equivalents except they return the class and call their iterators with the `this` value as the model by default.
* `Model.add()` now only takes a single argument.
-## 0.10.0
+## 0.10.0 - 1/3/11
* Add `extend()` and `include()` methods to add class and instance methods respectively.
* New declaration syntax - pass a function giving you access to the newly created class instead of two separate objects.
* A model with an id will be added to the collection when saved (like the docs said originally).
* `count()` now follows suit with the rest of js-model and returns the number of models in `all()` allowing you to overwrite `all()` with your own custom implementation - or "Eggs Fish Ham" as he put it ;) [Mark Evans]
-## 0.9.4
+## 0.9.4 - 6/12/10
* Add `Model.map()` method.
* Protect the collection from accidental modification allowing you to safely `remove()` a model from within an `each` loop.
* Added configurable Model.unique_key, exposed as instance.id() and used in finders. Defaults to 'id'. [Ismael Celis and Oliver Nightingale]
* Protect an instance's initial attributes from accidental modification.
-## 0.9.3
+## 0.9.3 - 28/9/10
* Add the ability to define a custom `initialize()` instance method that is called at the end of the initialization process. Thanks to Ismael Celis for the idea.
-## 0.9.2
+## 0.9.2 - 23/9/10
* Ajax DELETE sends JSON body, including AjaxSetup data if available. [Ismael Celis]
* `Model.remove()` should include removed instance in event data. [Ismael Celis]
* Call the `Model.load()` callback with the scope of the class.
-## 0.9.1
+## 0.9.1 - 21/9/10
* If defined, include jQuery.ajaxSetup data in REST parameters. [Ismael Celis]
-## 0.9.0
+## 0.9.0 - 16/9/10
* Finder methods now return `undefined` for a missing model.
* Remove #update method which you might guess acts like ActiveRecord's #update_attributes which is not the case - no calls are triggered on the persistence adapter.
@@ -51,37 +56,37 @@
* Add `pluck` method that takes an attribute name and returns an array of values.
* Fix for callbacks being wrongly called on multiple instances - they were being stored on the prototype and thus being shared across instances. Thanks to Oliver Nightingale for identifying the bug and writing a test case.
-## 0.8.4
+## 0.8.4 - 2/7/10
* Add named parameters to `Model.RestPersistence` so "/categories/:category_id/posts" will pick up the corresponding `category_id` attribute from your model and be converted to "/categories/2/posts". [Russell Jones]
-## 0.8.3
+## 0.8.3 - 15/4/10
* Fix that `find`, `first`, `last` and `detect` return `null` when nothing is found.
* Add `unbind` method to unbind all callbacks for a particular event or a specific callback by passing a reference to the original function.
* Move callback functionality into a separate module and mix-in to class and instance.
-## 0.8.2
+## 0.8.2 - 7/4/10
* Don't log an error when Rails returns a response of " " for a `head :ok` response.
* `jQuery.ajax` should use `dataType` "json" removing the need to set a global `beforeSend`. [Jason Lee]
-## 0.8.1
+## 0.8.1 - 29/3/10
* Fix that custom class methods should be available after chaining.
-## 0.8.0
+## 0.8.0 - 21/3/10
* Move model collection methods into a separate object allowing you to customise the defaults in a single place.
* Move model instance methods into a separate object. This allows you to redefine the defaults once rather than having to pass the same custom method to multiple models at declaration time.
* Defining a model now takes three arguments: name, class methods, instance methods.
-## 0.7.3
+## 0.7.3 - 10/3/10
* Fix callbacks in IE.
* Fix broken Ajax tests in IE6 and IE7.
-## 0.7.1
+## 0.7.1 - 5/3/10
* `Model.RestPersistence` now recognises a 422 response as validation failure and populates the model's errors object with the response data.
* `Model.errors` is now an object and has a similar interface to ActiveModel.
@@ -91,26 +96,26 @@
* Add `count` method to `Model.Collection`.
* Collection methods now access the collection through the `all` method so that `select`, `each`, etc work as expected if it's overwritten.
-## 0.7.0
+## 0.7.0 - 18/2/10
* Events are now bound directly to a model rather than using jQuery `bind`. Collections also now have the concept of events with "add" and "remove" built-in.
-## 0.6.1
+## 0.6.1 - 12/2/10
* `update` should trigger "update" event, add separate `merge` method.
* Fix that persistence failure should not trigger corresponding event.
-## 0.6.0
+## 0.6.0 - 11/2/10
* Pass only a single callback to save/destroy which is called with a boolean to indicate success/failure.
* Bundle release into a single, versioned Javascript file plus minified version.
* Change behaviour of `Model.Collection` and don't let duplicates (scoped by id) of the same model to be stored. [Laurie Young]
-## 0.5.1
+## 0.5.1 - 3/2/10
* Fix that setting a null value with `attr` should be read back correctly from `changes`.
* `errors` array shouldn't have to be manually `reset` when implementing `validate`.
-## 0.5.0
+## 0.5.0 - 3/2/10
* First tagged release.
View
2 VERSION
@@ -1 +1 @@
-0.10.1
+0.11.0
View
718 dist/js-model-0.11.0.js
@@ -0,0 +1,718 @@
+/* js-model JavaScript library, version 0.11.0
+ * (c) 2010-2012 Ben Pickles
+ *
+ * Released under MIT license.
+ */
+var Model = function(name, func) {
+ // The model constructor.
+ var model = function(attributes) {
+ this.attributes = Model.Utils.extend({}, attributes)
+ this.changes = {};
+ this.errors = new Model.Errors(this);
+ this.uid = [name, Model.UID.generate()].join("-")
+ if (Model.Utils.isFunction(this.initialize)) this.initialize()
+ };
+
+ // Use module functionality to extend itself onto the constructor. Meta!
+ Model.Module.extend.call(model, Model.Module)
+
+ model._name = name
+ model.collection = []
+ model.unique_key = "id"
+ model
+ .extend(Model.Callbacks)
+ .extend(Model.ClassMethods)
+
+ model.prototype = new Model.Base
+ model.prototype.constructor = model
+
+ if (Model.Utils.isFunction(func)) func.call(model, model, model.prototype)
+
+ return model;
+};
+
+Model.Callbacks = {
+ bind: function(event, callback) {
+ this.callbacks = this.callbacks || {}
+ this.callbacks[event] = this.callbacks[event] || [];
+ this.callbacks[event].push(callback);
+ return this;
+ },
+
+ trigger: function(name, data) {
+ this.callbacks = this.callbacks || {}
+
+ var callbacks = this.callbacks[name];
+
+ if (callbacks) {
+ for (var i = 0; i < callbacks.length; i++) {
+ callbacks[i].apply(this, data || []);
+ }
+ }
+
+ return this;
+ },
+
+ unbind: function(event, callback) {
+ this.callbacks = this.callbacks || {}
+
+ if (callback) {
+ var callbacks = this.callbacks[event] || [];
+
+ for (var i = 0; i < callbacks.length; i++) {
+ if (callbacks[i] === callback) {
+ this.callbacks[event].splice(i, 1);
+ }
+ }
+ } else {
+ delete this.callbacks[event];
+ }
+
+ return this;
+ }
+};
+
+Model.ClassMethods = {
+ add: function(model) {
+ var id = model.id()
+
+ if (Model.Utils.inArray(this.collection, model) === -1 && !(id && this.find(id))) {
+ this.collection.push(model)
+ this.trigger("add", [model])
+ }
+
+ return this;
+ },
+
+ all: function() {
+ return this.collection.slice()
+ },
+
+ // Convenience method to allow a simple method of chaining class methods.
+ chain: function(collection) {
+ return Model.Utils.extend({}, this, { collection: collection || [] })
+ },
+
+ count: function() {
+ return this.all().length;
+ },
+
+ detect: function(func) {
+ var all = this.all(),
+ model
+
+ for (var i = 0, length = all.length; i < length; i++) {
+ model = all[i]
+ if (func.call(model, model, i)) return model
+ }
+ },
+
+ each: function(func, context) {
+ var all = this.all()
+
+ for (var i = 0, length = all.length; i < length; i++) {
+ func.call(context || all[i], all[i], i, all)
+ }
+
+ return this;
+ },
+
+ find: function(id) {
+ return this.detect(function() {
+ return this.id() == id;
+ })
+ },
+
+ first: function() {
+ return this.all()[0]
+ },
+
+ load: function(callback) {
+ if (this._persistence) {
+ var self = this
+
+ this._persistence.read(function(models) {
+ for (var i = 0, length = models.length; i < length; i++) {
+ self.add(models[i])
+ }
+
+ if (callback) callback.call(self, models)
+ })
+ }
+
+ return this
+ },
+
+ last: function() {
+ var all = this.all();
+ return all[all.length - 1]
+ },
+
+ map: function(func, context) {
+ var all = this.all()
+ var values = []
+
+ for (var i = 0, length = all.length; i < length; i++) {
+ values.push(func.call(context || all[i], all[i], i, all))
+ }
+
+ return values
+ },
+
+ persistence: function(adapter) {
+ if (arguments.length == 0) {
+ return this._persistence
+ } else {
+ var options = Array.prototype.slice.call(arguments, 1)
+ options.unshift(this)
+ this._persistence = adapter.apply(adapter, options)
+ return this
+ }
+ },
+
+ pluck: function(attribute) {
+ var all = this.all()
+ var plucked = []
+
+ for (var i = 0, length = all.length; i < length; i++) {
+ plucked.push(all[i].attr(attribute))
+ }
+
+ return plucked
+ },
+
+ remove: function(model) {
+ var index
+
+ for (var i = 0, length = this.collection.length; i < length; i++) {
+ if (this.collection[i] === model) {
+ index = i
+ break
+ }
+ }
+
+ if (index != undefined) {
+ this.collection.splice(index, 1);
+ this.trigger("remove", [model]);
+ return true;
+ } else {
+ return false;
+ }
+ },
+
+ reverse: function() {
+ return this.chain(this.all().reverse())
+ },
+
+ select: function(func, context) {
+ var all = this.all(),
+ selected = [],
+ model
+
+ for (var i = 0, length = all.length; i < length; i++) {
+ model = all[i]
+ if (func.call(context || model, model, i, all)) selected.push(model)
+ }
+
+ return this.chain(selected);
+ },
+
+ sort: function(func) {
+ var sorted = this.all().sort(func)
+ return this.chain(sorted);
+ },
+
+ sortBy: function(attribute_or_func) {
+ var is_func = Model.Utils.isFunction(attribute_or_func)
+ var extract = function(model) {
+ return attribute_or_func.call(model)
+ }
+
+ return this.sort(function(a, b) {
+ var a_attr = is_func ? extract(a) : a.attr(attribute_or_func)
+ var b_attr = is_func ? extract(b) : b.attr(attribute_or_func)
+
+ if (a_attr < b_attr) {
+ return -1
+ } else if (a_attr > b_attr) {
+ return 1
+ } else {
+ return 0
+ }
+ })
+ },
+
+ use: function(plugin) {
+ var args = Array.prototype.slice.call(arguments, 1)
+ args.unshift(this)
+ plugin.apply(this, args)
+ return this
+ }
+};
+
+Model.Errors = function(model) {
+ this.errors = {};
+ this.model = model;
+};
+
+Model.Errors.prototype = {
+ add: function(attribute, message) {
+ if (!this.errors[attribute]) this.errors[attribute] = [];
+ this.errors[attribute].push(message);
+ return this
+ },
+
+ all: function() {
+ return this.errors;
+ },
+
+ clear: function() {
+ this.errors = {};
+ return this
+ },
+
+ each: function(func) {
+ for (var attribute in this.errors) {
+ for (var i = 0; i < this.errors[attribute].length; i++) {
+ func.call(this, attribute, this.errors[attribute][i]);
+ }
+ }
+ return this
+ },
+
+ on: function(attribute) {
+ return this.errors[attribute] || [];
+ },
+
+ size: function() {
+ var count = 0;
+ this.each(function() { count++; });
+ return count;
+ }
+};
+
+Model.InstanceMethods = {
+ asJSON: function() {
+ return this.attr()
+ },
+
+ attr: function(name, value) {
+ if (arguments.length === 0) {
+ // Combined attributes/changes object.
+ return Model.Utils.extend({}, this.attributes, this.changes);
+ } else if (arguments.length === 2) {
+ // Don't write to attributes yet, store in changes for now.
+ if (this.attributes[name] === value) {
+ // Clean up any stale changes.
+ delete this.changes[name];
+ } else {
+ this.changes[name] = value;
+ }
+ this.trigger("change:" + name, [this])
+ return this;
+ } else if (typeof name === "object") {
+ // Mass-assign attributes.
+ for (var key in name) {
+ this.attr(key, name[key]);
+ }
+ this.trigger("change", [this])
+ return this;
+ } else {
+ // Changes take precedent over attributes.
+ return (name in this.changes) ?
+ this.changes[name] :
+ this.attributes[name];
+ }
+ },
+
+ callPersistMethod: function(method, callback) {
+ var self = this;
+
+ // Automatically manage adding and removing from the model's Collection.
+ var manageCollection = function() {
+ if (method === "destroy") {
+ self.constructor.remove(self)
+ } else {
+ self.constructor.add(self)
+ }
+ };
+
+ // Wrap the existing callback in this function so we always manage the
+ // collection and trigger events from here rather than relying on the
+ // persistence adapter to do it for us. The persistence adapter is
+ // only required to execute the callback with a single argument - a
+ // boolean to indicate whether the call was a success - though any
+ // other arguments will also be forwarded to the original callback.
+ var wrappedCallback = function(success) {
+ if (success) {
+ // Merge any changes into attributes and clear changes.
+ self.merge(self.changes).reset();
+
+ // Add/remove from collection if persist was successful.
+ manageCollection();
+
+ // Trigger the event before executing the callback.
+ self.trigger(method);
+ }
+
+ // Store the return value of the callback.
+ var value;
+
+ // Run the supplied callback.
+ if (callback) value = callback.apply(self, arguments);
+
+ return value;
+ };
+
+ if (this.constructor._persistence) {
+ this.constructor._persistence[method](this, wrappedCallback);
+ } else {
+ wrappedCallback.call(this, true);
+ }
+ },
+
+ destroy: function(callback) {
+ this.callPersistMethod("destroy", callback);
+ return this;
+ },
+
+ id: function() {
+ return this.attributes[this.constructor.unique_key];
+ },
+
+ merge: function(attributes) {
+ Model.Utils.extend(this.attributes, attributes);
+ return this;
+ },
+
+ newRecord: function() {
+ return this.id() === undefined
+ },
+
+ reset: function() {
+ this.errors.clear();
+ this.changes = {};
+ return this;
+ },
+
+ save: function(callback) {
+ if (this.valid()) {
+ var method = this.newRecord() ? "create" : "update";
+ this.callPersistMethod(method, callback);
+ } else if (callback) {
+ callback(false);
+ }
+
+ return this;
+ },
+
+ valid: function() {
+ this.errors.clear();
+ this.validate();
+ return this.errors.size() === 0;
+ },
+
+ validate: function() {
+ return this;
+ }
+};
+
+Model.localStorage = function(klass) {
+ if (!window.localStorage) {
+ return {
+ create: function(model, callback) {
+ callback(true)
+ },
+
+ destroy: function(model, callback) {
+ callback(true)
+ },
+
+ read: function(callback) {
+ callback([])
+ },
+
+ update: function(model, callback) {
+ callback(true)
+ }
+ }
+ }
+
+ var collection_uid = [klass._name, "collection"].join("-")
+ var readIndex = function() {
+ var data = localStorage[collection_uid]
+ return data ? JSON.parse(data) : []
+ }
+ var writeIndex = function(uids) {
+ localStorage.setItem(collection_uid, JSON.stringify(uids))
+ }
+ var addToIndex = function(uid) {
+ var uids = readIndex()
+
+ if (Model.Utils.inArray(uids, uid) === -1) {
+ uids.push(uid)
+ writeIndex(uids)
+ }
+ }
+ var removeFromIndex = function(uid) {
+ var uids = readIndex()
+ var index = Model.Utils.inArray(uids, uid)
+
+ if (index > -1) {
+ uids.splice(index, 1)
+ writeIndex(uids)
+ }
+ }
+ var store = function(model) {
+ localStorage.setItem(model.uid, JSON.stringify(model.asJSON()))
+ addToIndex(model.uid)
+ }
+
+ return {
+ create: function(model, callback) {
+ store(model)
+ callback(true)
+ },
+
+ destroy: function(model, callback) {
+ localStorage.removeItem(model.uid)
+ removeFromIndex(model.uid)
+ callback(true)
+ },
+
+ read: function(callback) {
+ if (!callback) return false
+
+ var existing_uids = klass.map(function() { return this.uid })
+ var uids = readIndex()
+ var models = []
+ var attributes, model, uid
+
+ for (var i = 0, length = uids.length; i < length; i++) {
+ uid = uids[i]
+
+ if (Model.Utils.inArray(existing_uids, uid) == -1) {
+ attributes = JSON.parse(localStorage[uid])
+ model = new klass(attributes)
+ model.uid = uid
+ models.push(model)
+ }
+ }
+
+ callback(models)
+ },
+
+ update: function(model, callback) {
+ store(model)
+ callback(true)
+ }
+ }
+};
+
+Model.Log = function() {
+ if (window.console) window.console.log.apply(window.console, arguments);
+};
+
+Model.Module = {
+ extend: function(obj) {
+ Model.Utils.extend(this, obj)
+ return this
+ },
+
+ include: function(obj) {
+ Model.Utils.extend(this.prototype, obj)
+ return this
+ }
+};
+
+Model.REST = function(klass, resource, methods) {
+ var PARAM_NAME_MATCHER = /:([\w\d]+)/g;
+ var resource_param_names = (function() {
+ var resource_param_names = []
+ var param_name
+
+ while ((param_name = PARAM_NAME_MATCHER.exec(resource)) !== null) {
+ resource_param_names.push(param_name[1])
+ }
+
+ return resource_param_names
+ })()
+
+ return Model.Utils.extend({
+ path: function(model) {
+ var path = resource;
+ jQuery.each(resource_param_names, function(i, param) {
+ path = path.replace(":" + param, model.attributes[param]);
+ });
+ return path;
+ },
+
+ create: function(model, callback) {
+ return this.xhr('POST', this.create_path(model), model, callback);
+ },
+
+ create_path: function(model) {
+ return this.path(model);
+ },
+
+ destroy: function(model, callback) {
+ return this.xhr('DELETE', this.destroy_path(model), model, callback);
+ },
+
+ destroy_path: function(model) {
+ return this.update_path(model);
+ },
+
+ params: function(model) {
+ var params;
+ if (model) {
+ var attributes = model.asJSON()
+ delete attributes[model.constructor.unique_key];
+ params = {};
+ params[model.constructor._name.toLowerCase()] = attributes;
+ } else {
+ params = null;
+ }
+ if(jQuery.ajaxSettings.data){
+ params = Model.Utils.extend({}, jQuery.ajaxSettings.data, params)
+ }
+ return JSON.stringify(params)
+ },
+
+ read: function(callback) {
+ return this.xhr("GET", this.read_path(), null, function(success, xhr, data) {
+ data = jQuery.makeArray(data)
+ var models = []
+
+ for (var i = 0, length = data.length; i < length; i++) {
+ models.push(new klass(data[i]))
+ }
+
+ callback(models)
+ })
+ },
+
+ read_path: function() {
+ return resource
+ },
+
+ update: function(model, callback) {
+ return this.xhr('PUT', this.update_path(model), model, callback);
+ },
+
+ update_path: function(model) {
+ return [this.path(model), model.id()].join('/');
+ },
+
+ xhr: function(method, url, model, callback) {
+ var self = this;
+ var data = method == 'GET' ? undefined : this.params(model);
+
+ return jQuery.ajax({
+ type: method,
+ url: url,
+ contentType: "application/json",
+ dataType: "json",
+ data: data,
+ dataFilter: function(data, type) {
+ return /\S/.test(data) ? data : undefined;
+ },
+ complete: function(xhr, textStatus) {
+ self.xhrComplete(xhr, textStatus, model, callback)
+ }
+ });
+ },
+
+ xhrComplete: function(xhr, textStatus, model, callback) {
+ // Allow custom handlers to be defined per-HTTP status code.
+ var handler = Model.REST["handle" + xhr.status]
+ if (handler) handler.call(this, xhr, textStatus, model)
+
+ var success = textStatus === "success"
+ var data = Model.REST.parseResponseData(xhr)
+
+ // Remote data is the definitive source, update model.
+ if (success && model && data) model.attr(data)
+
+ if (callback) callback.call(model, success, xhr, data)
+ }
+ }, methods)
+};
+
+// TODO: Remove in v1 if it ever gets there.
+Model.RestPersistence = Model.REST;
+
+// Rails' preferred failed validation response code, assume the response
+// contains errors and replace current model errors with them.
+Model.REST.handle422 = function(xhr, textStatus, model) {
+ var data = Model.REST.parseResponseData(xhr);
+
+ if (data) {
+ model.errors.clear()
+
+ for (var attribute in data) {
+ for (var i = 0; i < data[attribute].length; i++) {
+ model.errors.add(attribute, data[attribute][i])
+ }
+ }
+ }
+};
+
+Model.REST.parseResponseData = function(xhr) {
+ try {
+ return /\S/.test(xhr.responseText) ?
+ jQuery.parseJSON(xhr.responseText) :
+ undefined;
+ } catch(e) {
+ Model.Log(e);
+ }
+};
+
+Model.UID = {
+ counter: 0,
+
+ generate: function() {
+ return [new Date().valueOf(), this.counter++].join("-")
+ },
+
+ reset: function() {
+ this.counter = 0
+ return this
+ }
+};
+
+Model.Utils = {
+ extend: function(receiver) {
+ var objs = Array.prototype.slice.call(arguments, 1)
+
+ for (var i = 0, length = objs.length; i < length; i++) {
+ for (var property in objs[i]) {
+ receiver[property] = objs[i][property]
+ }
+ }
+
+ return receiver
+ },
+
+ inArray: function(array, obj) {
+ if (array.indexOf) return array.indexOf(obj)
+
+ for (var i = 0, length = array.length; i < length; i++) {
+ if (array[i] === obj) return i
+ }
+
+ return -1
+ },
+
+ isFunction: function(obj) {
+ return Object.prototype.toString.call(obj) === "[object Function]"
+ }
+}
+
+Model.VERSION = "0.11.0";
+
+Model.Base = (function() {
+ function Base() {}
+ Base.prototype = Model.Utils.extend({}, Model.Callbacks, Model.InstanceMethods)
+ return Base
+})();
View
23 dist/js-model-0.11.0.min.js
@@ -0,0 +1,23 @@
+/* js-model JavaScript library, version 0.11.0
+ * (c) 2010-2012 Ben Pickles
+ *
+ * Released under MIT license.
+ */
+var Model=function(a,c){var b=function(e){this.attributes=Model.Utils.extend({},e);this.changes={};this.errors=new Model.Errors(this);this.uid=[a,Model.UID.generate()].join("-");Model.Utils.isFunction(this.initialize)&&this.initialize()};Model.Module.extend.call(b,Model.Module);b._name=a;b.collection=[];b.unique_key="id";b.extend(Model.Callbacks).extend(Model.ClassMethods);b.prototype=new Model.Base;b.prototype.constructor=b;Model.Utils.isFunction(c)&&c.call(b,b,b.prototype);return b};
+Model.Callbacks={bind:function(a,c){this.callbacks=this.callbacks||{};this.callbacks[a]=this.callbacks[a]||[];this.callbacks[a].push(c);return this},trigger:function(a,c){this.callbacks=this.callbacks||{};var b=this.callbacks[a];if(b)for(var e=0;e<b.length;e++)b[e].apply(this,c||[]);return this},unbind:function(a,c){this.callbacks=this.callbacks||{};if(c)for(var b=this.callbacks[a]||[],e=0;e<b.length;e++)b[e]===c&&this.callbacks[a].splice(e,1);else delete this.callbacks[a];return this}};
+Model.ClassMethods={add:function(a){var c=a.id();if(Model.Utils.inArray(this.collection,a)===-1&&!(c&&this.find(c))){this.collection.push(a);this.trigger("add",[a])}return this},all:function(){return this.collection.slice()},chain:function(a){return Model.Utils.extend({},this,{collection:a||[]})},count:function(){return this.all().length},detect:function(a){for(var c=this.all(),b,e=0,f=c.length;e<f;e++){b=c[e];if(a.call(b,b,e))return b}},each:function(a,c){for(var b=this.all(),e=0,f=b.length;e<f;e++)a.call(c||
+b[e],b[e],e,b);return this},find:function(a){return this.detect(function(){return this.id()==a})},first:function(){return this.all()[0]},load:function(a){if(this._persistence){var c=this;this._persistence.read(function(b){for(var e=0,f=b.length;e<f;e++)c.add(b[e]);a&&a.call(c,b)})}return this},last:function(){var a=this.all();return a[a.length-1]},map:function(a,c){for(var b=this.all(),e=[],f=0,d=b.length;f<d;f++)e.push(a.call(c||b[f],b[f],f,b));return e},persistence:function(a){if(arguments.length==
+0)return this._persistence;else{var c=Array.prototype.slice.call(arguments,1);c.unshift(this);this._persistence=a.apply(a,c);return this}},pluck:function(a){for(var c=this.all(),b=[],e=0,f=c.length;e<f;e++)b.push(c[e].attr(a));return b},remove:function(a){for(var c,b=0,e=this.collection.length;b<e;b++)if(this.collection[b]===a){c=b;break}if(c!=undefined){this.collection.splice(c,1);this.trigger("remove",[a]);return true}else return false},reverse:function(){return this.chain(this.all().reverse())},
+select:function(a,c){for(var b=this.all(),e=[],f,d=0,g=b.length;d<g;d++){f=b[d];if(a.call(c||f,f,d,b))e.push(f)}return this.chain(e)},sort:function(a){return this.chain(this.all().sort(a))},sortBy:function(a){var c=Model.Utils.isFunction(a);return this.sort(function(b,e){var f=c?a.call(b):b.attr(a),d=c?a.call(e):e.attr(a);return f<d?-1:f>d?1:0})},use:function(a){var c=Array.prototype.slice.call(arguments,1);c.unshift(this);a.apply(this,c);return this}};
+Model.Errors=function(a){this.errors={};this.model=a};Model.Errors.prototype={add:function(a,c){this.errors[a]||(this.errors[a]=[]);this.errors[a].push(c);return this},all:function(){return this.errors},clear:function(){this.errors={};return this},each:function(a){for(var c in this.errors)for(var b=0;b<this.errors[c].length;b++)a.call(this,c,this.errors[c][b]);return this},on:function(a){return this.errors[a]||[]},size:function(){var a=0;this.each(function(){a++});return a}};
+Model.InstanceMethods={asJSON:function(){return this.attr()},attr:function(a,c){if(arguments.length===0)return Model.Utils.extend({},this.attributes,this.changes);else if(arguments.length===2){if(this.attributes[a]===c)delete this.changes[a];else this.changes[a]=c;this.trigger("change:"+a,[this]);return this}else if(typeof a==="object"){for(var b in a)this.attr(b,a[b]);this.trigger("change",[this]);return this}else return a in this.changes?this.changes[a]:this.attributes[a]},callPersistMethod:function(a,
+c){var b=this,e=function(f){if(f){b.merge(b.changes).reset();a==="destroy"?b.constructor.remove(b):b.constructor.add(b);b.trigger(a)}var d;if(c)d=c.apply(b,arguments);return d};if(this.constructor._persistence)this.constructor._persistence[a](this,e);else e.call(this,true)},destroy:function(a){this.callPersistMethod("destroy",a);return this},id:function(){return this.attributes[this.constructor.unique_key]},merge:function(a){Model.Utils.extend(this.attributes,a);return this},newRecord:function(){return this.id()===
+undefined},reset:function(){this.errors.clear();this.changes={};return this},save:function(a){if(this.valid())this.callPersistMethod(this.newRecord()?"create":"update",a);else a&&a(false);return this},valid:function(){this.errors.clear();this.validate();return this.errors.size()===0},validate:function(){return this}};
+Model.localStorage=function(a){if(!window.localStorage)return{create:function(f,d){d(true)},destroy:function(f,d){d(true)},read:function(f){f([])},update:function(f,d){d(true)}};var c=[a._name,"collection"].join("-"),b=function(){var f=localStorage[c];return f?JSON.parse(f):[]},e=function(f){localStorage.setItem(f.uid,JSON.stringify(f.asJSON()));f=f.uid;var d=b();if(Model.Utils.inArray(d,f)===-1){d.push(f);localStorage.setItem(c,JSON.stringify(d))}};return{create:function(f,d){e(f);d(true)},destroy:function(f,
+d){localStorage.removeItem(f.uid);var g=f.uid,h=b();g=Model.Utils.inArray(h,g);if(g>-1){h.splice(g,1);localStorage.setItem(c,JSON.stringify(h))}d(true)},read:function(f){if(!f)return false;for(var d=a.map(function(){return this.uid}),g=b(),h=[],i,j,l=0,k=g.length;l<k;l++){j=g[l];if(Model.Utils.inArray(d,j)==-1){i=JSON.parse(localStorage[j]);i=new a(i);i.uid=j;h.push(i)}}f(h)},update:function(f,d){e(f);d(true)}}};Model.Log=function(){window.console&&window.console.log.apply(window.console,arguments)};
+Model.Module={extend:function(a){Model.Utils.extend(this,a);return this},include:function(a){Model.Utils.extend(this.prototype,a);return this}};
+Model.REST=function(a,c,b){var e=/:([\w\d]+)/g,f=function(){for(var d=[],g;(g=e.exec(c))!==null;)d.push(g[1]);return d}();return Model.Utils.extend({path:function(d){var g=c;jQuery.each(f,function(h,i){g=g.replace(":"+i,d.attributes[i])});return g},create:function(d,g){return this.xhr("POST",this.create_path(d),d,g)},create_path:function(d){return this.path(d)},destroy:function(d,g){return this.xhr("DELETE",this.destroy_path(d),d,g)},destroy_path:function(d){return this.update_path(d)},params:function(d){var g;
+if(d){var h=d.asJSON();delete h[d.constructor.unique_key];g={};g[d.constructor._name.toLowerCase()]=h}else g=null;if(jQuery.ajaxSettings.data)g=Model.Utils.extend({},jQuery.ajaxSettings.data,g);return JSON.stringify(g)},read:function(d){return this.xhr("GET",this.read_path(),null,function(g,h,i){i=jQuery.makeArray(i);g=[];h=0;for(var j=i.length;h<j;h++)g.push(new a(i[h]));d(g)})},read_path:function(){return c},update:function(d,g){return this.xhr("PUT",this.update_path(d),d,g)},update_path:function(d){return[this.path(d),
+d.id()].join("/")},xhr:function(d,g,h,i){var j=this,l=d=="GET"?undefined:this.params(h);return jQuery.ajax({type:d,url:g,contentType:"application/json",dataType:"json",data:l,dataFilter:function(k){return/\S/.test(k)?k:undefined},complete:function(k,m){j.xhrComplete(k,m,h,i)}})},xhrComplete:function(d,g,h,i){var j=Model.REST["handle"+d.status];j&&j.call(this,d,g,h);g=g==="success";j=Model.REST.parseResponseData(d);g&&h&&j&&h.attr(j);i&&i.call(h,g,d,j)}},b)};Model.RestPersistence=Model.REST;
+Model.REST.handle422=function(a,c,b){if(a=Model.REST.parseResponseData(a)){b.errors.clear();for(var e in a)for(c=0;c<a[e].length;c++)b.errors.add(e,a[e][c])}};Model.REST.parseResponseData=function(a){try{return/\S/.test(a.responseText)?jQuery.parseJSON(a.responseText):undefined}catch(c){Model.Log(c)}};Model.UID={counter:0,generate:function(){return[(new Date).valueOf(),this.counter++].join("-")},reset:function(){this.counter=0;return this}};
+Model.Utils={extend:function(a){for(var c=Array.prototype.slice.call(arguments,1),b=0,e=c.length;b<e;b++)for(var f in c[b])a[f]=c[b][f];return a},inArray:function(a,c){if(a.indexOf)return a.indexOf(c);for(var b=0,e=a.length;b<e;b++)if(a[b]===c)return b;return-1},isFunction:function(a){return Object.prototype.toString.call(a)==="[object Function]"}};Model.VERSION="0.11.0";Model.Base=function(){function a(){}a.prototype=Model.Utils.extend({},Model.Callbacks,Model.InstanceMethods);return a}();
View
105 index.html
@@ -1,7 +1,8 @@
<!DOCTYPE html>
<html lang="en">
<head>
-<title>js-model &bull; models in your JavaScript</title>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>js-model • models in your JavaScript</title>
<link href="docs/style.css" rel="stylesheet">
<script type="text/javascript">
var _gaq = _gaq || [];
@@ -17,23 +18,21 @@
</head>
<body>
<div id="content">
- <h1>js-model (0.10.1)</h1>
+ <h1>js-model (0.11.0)</h1>
- <p>js-model is a library built on top of <a href="http://jquery.com/">jQuery</a> that allows you to work with models in your JavaScript.</p>
+ <p>js-model is a library that allows you to work with models in your JavaScript.</p>
<dl>
<dt>Download</dt>
<dd>
-<a href="dist/js-model-0.10.1.min.js">js-model-0.10.1.min.js</a> (8.1Kb)</dd>
+<a href="dist/js-model-0.11.0.min.js">js-model-0.11.0.min.js</a> (8.6Kb)</dd>
<dd>
-<a href="dist/js-model-0.10.1.js">js-model-0.10.1.js</a> (16.2Kb)</dd>
+<a href="dist/js-model-0.11.0.js">js-model-0.11.0.js</a> (16.9Kb)</dd>
<dt>Source</dt>
<dd><a href="http://github.com/benpickles/js-model">github.com/benpickles/js-model</a></dd>
</dl>
-<div class="archive"><a href="docs/v0.9.4.html">Version 0.9.4 docs</a></div>
-
- <nav><ol>
+<nav><ol>
<li>
<a href="#getting-started">Getting started</a><ol>
<li><a href="#manipulating-objects">Manipulating objects</a></li>
@@ -62,7 +61,7 @@
<li><a href="#loading-data">Loading data</a></li>
</ol>
</li>
-<li><a href="#js-model-hearts-sammy">js-model &hearts; Sammy</a></li>
+<li><a href="#js-model-9829-sammy">js-model Sammy</a></li>
<li>
<a href="#api">API</a><ol>
<li><a href="#model">Model()</a></li>
@@ -137,7 +136,7 @@
<pre><code><span class="kd">var</span> <span class="nx">Project</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"project"</span><span class="p">)</span></code></pre>
-<p>This allows you to create instances of &ldquo;project&rdquo; models and also contains an internal collection of all &ldquo;projects&rdquo; which can be used for querying.</p>
+<p>This allows you to create instances of project models and also contains an internal collection of all projects which can be used for querying.</p>
<h3 id="manipulating-objects">Manipulating objects</h3>
@@ -149,7 +148,7 @@ <h3 id="manipulating-objects">Manipulating objects</h3>
<h3 id="finding-objects">Finding objects</h3>
-<p>After calling <a href="#save"><code>save()</code></a> on a model it is added to the class&rsquo;s &ldquo;collection&rdquo; and can be retrieved again by calling <a href="#find"><code>find()</code></a> (or <a href="#first"><code>first()</code></a> as it is the first model in the collection).</p>
+<p>After calling <a href="#save"><code>save()</code></a> on a model it is added to the class’s “collection and can be retrieved again by calling <a href="#find"><code>find()</code></a> (or <a href="#first"><code>first()</code></a> as it is the first model in the collection).</p>
<pre><code><span class="nx">Project</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="c1">// =&gt; project</span>
@@ -170,7 +169,7 @@ <h3 id="custom-properties">Custom properties</h3>
<h4 id="class-properties">Class properties</h4>
-<p>When <a href="#model">creating a model</a> you can pass a function as the optional second argument and &ldquo;<a href="#extend">extend</a>&rdquo; the class by adding methods to it.</p>
+<p>When <a href="#model">creating a model</a> you can pass a function as the optional second argument and <a href="#extend">extend</a> the class by adding methods to it.</p>
<pre><code><span class="kd">var</span> <span class="nx">Project</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">extend</span><span class="p">({</span>
@@ -187,7 +186,7 @@ <h4 id="class-properties">Class properties</h4>
<h4 id="instance-properties">Instance properties</h4>
-<p>You can also &ldquo;<a href="#include">include</a>&rdquo; instance methods on the model&rsquo;s prototype. These are often used to link objects together in a way that mimics the relationships the data might have in the remote database (&ldquo;has many&rdquo; etc). However, they can be pretty much anything and can overwrite the defaults.</p>
+<p>You can also <a href="#include">include</a> instance methods on the models prototype. These are often used to link objects together in a way that mimics the relationships the data might have in the remote database (has many etc). However, they can be pretty much anything and can overwrite the defaults.</p>
<pre><code><span class="kd">var</span> <span class="nx">Project</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">include</span><span class="p">({</span>
@@ -202,7 +201,7 @@ <h4 id="instance-properties">Instance properties</h4>
<h3 id="associations">Associations</h3>
-<p>Simple associations can be mimicked by adding a couple of instance methods. Here a <code>Cat</code> &ldquo;belongs to&rdquo; a <code>Mat</code> and a <code>Mat</code> &ldquo;has many&rdquo; <code>Cat</code>s.</p>
+<p>Simple associations can be mimicked by adding a couple of instance methods. Here a <code>Cat</code> belongs to a <code>Mat</code> and a <code>Mat</code> has many <code>Cat</code>s.</p>
<pre><code><span class="kd">var</span> <span class="nx">Cat</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"cat"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">include</span><span class="p">({</span>
@@ -230,7 +229,7 @@ <h3 id="associations">Associations</h3>
<h3 id="events">Events</h3>
-<p>js-model allows you to listen to the lifecycle of objects based on the events they trigger at different points. Typically you&rsquo;ll use this to link your data objects to UI elements.</p>
+<p>js-model allows you to listen to the lifecycle of objects based on the events they trigger at different points. Typically youll use this to link your data objects to UI elements.</p>
<h4 id="class-events">Class events</h4>
@@ -272,16 +271,16 @@ <h4 id="custom-events">Custom events</h4>
<h3 id="validations">Validations</h3>
-<p>To add your own validations you should define a custom <a href="#validate"><code>validate()</code></a> method on your model that adds error messages to the <a href="#errors"><code>errors</code></a> object. <a href="#valid"><code>valid()</code></a> is called on <a href="#save"><code>save()</code></a> and checks that there are no errors. Validations are useful when using <a href="#localstorage">localStorage persistence</a> but can also help you avoid hitting your server unnecessarily if you&rsquo;re using <a href="#rest">REST persistence</a>.</p>
+<p>To add your own validations you should define a custom <a href="#validate"><code>validate()</code></a> method on your model that adds error messages to the <a href="#errors"><code>errors</code></a> object. <a href="#valid"><code>valid()</code></a> is called on <a href="#save"><code>save()</code></a> and checks that there are no errors. Validations are useful when using <a href="#localstorage">localStorage persistence</a> but can also help you avoid hitting your server unnecessarily if you’re using <a href="#rest">REST persistence</a>.</p>
</section><section><h2 id="persistence">Persistence</h2>
-<p>js-model is different to several other solutions, it&rsquo;s not a REST-based proxy for the objects on your server and doesn&rsquo;t rely on constant HTTP requests to gather information. Instead, it looks up objects in its own cache which can be populated via a persistence adapter &mdash; think of it as <a href="http://blog.new-bamboo.co.uk/2010/2/4/let-them-eat-state">maintaining the state of your objects in the browser</a>.</p>
+<p>js-model is different to several other solutions, its not a REST-based proxy for the objects on your server and doesnt rely on constant HTTP requests to gather information. Instead, it looks up objects in its own cache which can be populated via a persistence adapter think of it as <a href="http://blog.new-bamboo.co.uk/2010/2/4/let-them-eat-state">maintaining the state of your objects in the browser</a>.</p>
<p>Persistence is defined as a <a href="#class-properties">class property</a> and comes in two flavours: <a href="#rest">REST</a> and <a href="#localstorage">localStorage</a>. Both adapters encode/decode your attributes with JSON and so require the browser to be JSON-aware (or to include the <a href="http://www.json.org/js.html">JSON JavaScript library</a>). Persistence is defined using the <a href="#api-class-properties-persistence"><code>persistence()</code></a> method.</p>
<h3 id="rest">REST</h3>
-<p>Uses jQuery&rsquo;s <a href="http://api.jquery.com/jQuery.ajax/"><code>ajax()</code></a> method to GET, POST, PUT and DELETE model data to the server as JSON and expects JSON back.</p>
+<p>Uses jQuerys <a href="http://api.jquery.com/jQuery.ajax/"><code>ajax()</code></a> method to GET, POST, PUT and DELETE model data to the server as JSON and expects JSON back.</p>
<pre><code><span class="kd">var</span> <span class="nx">Project</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">persistence</span><span class="p">(</span><span class="nx">Model</span><span class="p">.</span><span class="nx">REST</span><span class="p">,</span> <span class="s2">"/projects"</span><span class="p">)</span>
@@ -294,33 +293,33 @@ <h3 id="rest">REST</h3>
<span class="nx">project</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s2">"name"</span><span class="p">,</span> <span class="s2">"nonsense"</span><span class="p">).</span><span class="nx">save</span><span class="p">()</span> <span class="c1">// PUT /projects/1</span>
<span class="nx">project</span><span class="p">.</span><span class="nx">destroy</span><span class="p">()</span> <span class="c1">// DELETE /projects/1</span></code></pre>
-<p>When responding to POST or PUT requests any JSON returned will be <a href="#merge">merged</a> into the model&rsquo;s <a href="#attributes"><code>attributes</code></a> &mdash; you should also make sure to include the id in the POST response so it can be assigned to the model. 422 responses from the server will be interpreted as having failed validations, any returned JSON will be assumed to be errors and replace client-side <a href="#api-errors"><code>errors</code></a>.</p>
+<p>When responding to POST or PUT requests any JSON returned will be <a href="#merge">merged</a> into the models <a href="#attributes"><code>attributes</code></a> you should also make sure to include the id in the POST response so it can be assigned to the model. 422 responses from the server will be interpreted as having failed validations, any returned JSON will be assumed to be errors and replace client-side <a href="#api-errors"><code>errors</code></a>.</p>
-<p><strong>Note:</strong> If you&rsquo;re using Rails you should make sure to add the following setting in an initializer as js-model expects non-namespaced JSON:</p>
+<p><strong>Note:</strong> If youre using Rails you should make sure to add the following setting in an initializer as js-model expects non-namespaced JSON:</p>
<pre><code><span class="no">ActiveRecord</span><span class="o">::</span><span class="no">Base</span><span class="o">.</span><span class="n">include_root_in_json</span> <span class="o">=</span> <span class="kp">false</span></code></pre>
<h3 id="localstorage">localStorage</h3>
-<p>localStorage is a client-side key/value store that persists between page views and browser sessions, it&rsquo;s supported by Safari, Chrome, Firefox, Opera, IE8 and Safari Mobile (iPhone) &mdash; WebKit-based browsers have an excellent localStorage GUI in the Web Inspector.</p>
+<p>localStorage is a client-side key/value store that persists between page views and browser sessions, its supported by Safari, Chrome, Firefox, Opera, IE8 and Safari Mobile (iPhone) WebKit-based browsers have an excellent localStorage GUI in the Web Inspector.</p>
<pre><code><span class="kd">var</span> <span class="nx">Project</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">persistence</span><span class="p">(</span><span class="nx">Model</span><span class="p">.</span><span class="nx">localStorage</span><span class="p">)</span>
<span class="p">})</span></code></pre>
<h3 id="loading-data">Loading data</h3>
-<p>If you have existing data stored in your persistence layer you&rsquo;ll want to be able to have it available when you next open your app. You&rsquo;ll typically call <a href="#load"><code>load()</code></a> when your document loads and perform an action when it has completed.</p>
+<p>If you have existing data stored in your persistence layer youll want to be able to have it available when you next open your app. Youll typically call <a href="#load"><code>load()</code></a> when your document loads and perform an action when it has completed.</p>
<pre><code><span class="c1">// wait for the document to load</span>
<span class="nx">$</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">Project</span><span class="p">.</span><span class="nx">load</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// do something with the UI</span>
<span class="p">})</span>
<span class="p">})</span></code></pre>
-</section><section><h2 id="js-model-hearts-sammy">js-model &hearts; Sammy</h2>
+</section><section><h2 id="js-model-9829-sammy">js-model Sammy</h2>
-<p>js-model works really well with Sammy &mdash; you <em>are</em> using <a href="http://code.quirkey.com/sammy/">Sammy</a> right? Your routes might look something like this:</p>
+<p>js-model works really well with Sammy you <em>are</em> using <a href="http://code.quirkey.com/sammy/">Sammy</a> right? Your routes might look something like this:</p>
<pre><code><span class="nx">$</span><span class="p">.</span><span class="nx">sammy</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">get</span><span class="p">(</span><span class="s2">"#/projects"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
@@ -411,7 +410,7 @@ <h3 id="api-class-properties">Class properties</h3>
<h4 id="add"><code>add(model)</code></h4>
-<p>Adds a model to a collection and is what <a href="#save"><code>save()</code></a> calls internally if it is successful. <code>add()</code> won&rsquo;t allow you to add a model to the collection if one already exists with the same <a href="#id"><code>id</code></a> or <a href="#uid"><code>uid</code></a>.</p>
+<p>Adds a model to a collection and is what <a href="#save"><code>save()</code></a> calls internally if it is successful. <code>add()</code> wont allow you to add a model to the collection if one already exists with the same <a href="#id"><code>id</code></a> or <a href="#uid"><code>uid</code></a>.</p>
<pre><code><span class="nx">Food</span><span class="p">.</span><span class="nx">all</span><span class="p">()</span>
<span class="c1">// =&gt; []</span>
@@ -448,7 +447,7 @@ <h4 id="all"><code>all()</code></h4>
<h4 id="chain"><code>chain(arrayOfModels)</code></h4>
-<p>A utility method to enable chaining methods on a collection &mdash; used internally by <a href="#select"><code>select()</code></a> for instance.</p>
+<p>A utility method to enable chaining methods on a collection used internally by <a href="#select"><code>select()</code></a> for instance.</p>
<h4 id="count"><code>count()</code></h4>
@@ -526,7 +525,7 @@ <h4 id="first"><code>first()</code></h4>
<h4 id="include"><code>include(object)</code></h4>
-<p>Add methods to the class&rsquo;s <code>prototype</code>.</p>
+<p>Add methods to the classs <code>prototype</code>.</p>
<pre><code><span class="nx">Food</span><span class="p">.</span><span class="nx">include</span><span class="p">({</span>
<span class="nx">reverseName</span><span class="o">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
@@ -538,7 +537,7 @@ <h4 id="include"><code>include(object)</code></h4>
<span class="nx">carrot</span><span class="p">.</span><span class="nx">reverseName</span><span class="p">()</span>
<span class="c1">// =&gt; "torraC"</span></code></pre>
-<p><strong>Note:</strong> Be careful when adding properties that aren&rsquo;t primitives to an object&rsquo;s <code>prototype</code>, this can result in unexpected behaviour as the <code>prototype</code> is shared across all instances, for example:</p>
+<p><strong>Note:</strong> Be careful when adding properties that arent primitives to an objects <code>prototype</code>, this can result in unexpected behaviour as the <code>prototype</code> is shared across all instances, for example:</p>
<pre><code><span class="kd">var</span> <span class="nx">Post</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"post"</span><span class="p">)</span>
<span class="nx">Post</span><span class="p">.</span><span class="nx">include</span><span class="p">({</span>
@@ -618,7 +617,7 @@ <h4 id="map"><code>map(func)</code></h4>
<h4 id="new"><code>new(attributes)</code></h4>
-<p>Instantiates a model, the supplied attributes get assigned directly to the model&rsquo;s <a href="#attributes"><code>attributes</code></a>. Custom initialization behaviour can be added by defining an <a href="#initialize"><code>initialize()</code></a> instance method.</p>
+<p>Instantiates a model, the supplied attributes get assigned directly to the models <a href="#attributes"><code>attributes</code></a>. Custom initialization behaviour can be added by defining an <a href="#initialize"><code>initialize()</code></a> instance method.</p>
<pre><code><span class="kd">var</span> <span class="nx">fish</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Food</span><span class="p">({</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">"fish"</span> <span class="p">})</span>
@@ -678,7 +677,7 @@ <h4 id="select"><code>select(func)</code></h4>
<h4 id="sort"><code>sort(func)</code></h4>
-<p>Acts like <code>Array#sort()</code> on the collection. It&rsquo;s more likely you&rsquo;ll want to use <a href="#sortby"><code>sortBy()</code></a> which is a far more convenient wrapper to <code>sort()</code>.</p>
+<p>Acts like <code>Array#sort()</code> on the collection. Its more likely youll want to use <a href="#sortby"><code>sortBy()</code></a> which is a far more convenient wrapper to <code>sort()</code>.</p>
<h4 id="sortby">
<code>sortBy(attributeName</code> or <code>func)</code>
@@ -696,7 +695,7 @@ <h4 id="sortby">
<h4 id="unique_key"><code>unique_key</code></h4>
-<p><code>unique_key</code> refers to the attribute that holds the &ldquo;primary key&rdquo; and defaults to <code>"id"</code>. It&rsquo;s useful when using with something like MongoDB.</p>
+<p><code>unique_key</code> refers to the attribute that holds the primary key and defaults to <code>"id"</code>. Its useful when using with something like MongoDB.</p>
<pre><code><span class="nx">Project</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">unique_key</span> <span class="o">=</span> <span class="s2">"_id"</span>
@@ -714,26 +713,26 @@ <h4 id="use"><code>use(Plugin, ...)</code></h4>
<span class="k">this</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">MyPlugin</span><span class="p">,</span> <span class="s2">"with"</span><span class="p">,</span> <span class="p">{</span> <span class="nx">extra</span><span class="o">:</span> <span class="s2">"arguments"</span> <span class="p">})</span>
<span class="p">})</span></code></pre>
-<p><code>use</code> can also be called outside of a model&rsquo;s declaration as it&rsquo;s simply a class method.</p>
+<p><code>use</code> can also be called outside of a models declaration as its simply a class method.</p>
<pre><code><span class="nx">Project</span><span class="p">.</span><span class="nx">use</span><span class="p">(</span><span class="nx">MyPlugin</span><span class="p">,</span> <span class="s2">"with"</span><span class="p">,</span> <span class="p">{</span> <span class="nx">extra</span><span class="o">:</span> <span class="s2">"arguments"</span> <span class="p">})</span></code></pre>
<h3 id="api-instance-properties">Instance properties</h3>
<h4 id="attr"><code>attr()</code></h4>
-<p>Get and set a model&rsquo;s attribute(s). <code>attr()</code> can be used in a few ways:</p>
+<p>Get and set a models attribute(s). <code>attr()</code> can be used in a few ways:</p>
<ul>
<li>
-<code>attr(name)</code> &mdash; Get the value of the named attribute.</li>
+<code>attr(name)</code> Get the value of the named attribute.</li>
<li>
-<code>attr(name, value)</code> &mdash; Set the value of the named attribute.</li>
+<code>attr(name, value)</code> Set the value of the named attribute.</li>
<li>
-<code>attr()</code> &mdash; Get an object containing all name/value attribute pairs.</li>
+<code>attr()</code> Get an object containing all name/value attribute pairs.</li>
<li>
-<code>attr(object)</code> &mdash; Set multiple name/value attribute pairs.</li>
+<code>attr(object)</code> Set multiple name/value attribute pairs.</li>
</ul>
-<p>Attributes modified using <code>attr()</code> can be reverted &mdash; see <a href="#changes"><code>changes</code></a> for more information.</p>
+<p>Attributes modified using <code>attr()</code> can be reverted see <a href="#changes"><code>changes</code></a> for more information.</p>
<pre><code><span class="kd">var</span> <span class="nx">project</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Project</span><span class="p">({</span> <span class="nx">title</span><span class="o">:</span> <span class="s2">"Foo"</span><span class="p">,</span> <span class="nx">category</span><span class="o">:</span> <span class="s2">"Stuff"</span> <span class="p">})</span>
@@ -763,15 +762,15 @@ <h4 id="attr"><code>attr()</code></h4>
<h4 id="attributes"><code>attributes</code></h4>
-<p>Direct access to a model&rsquo;s attributes object. Most of the time you won&rsquo;t need to use this and should use <a href="#attr"><code>attr()</code></a> instead.</p>
+<p>Direct access to a models attributes object. Most of the time you wont need to use this and should use <a href="#attr"><code>attr()</code></a> instead.</p>
<pre><code><span class="kd">var</span> <span class="nx">project</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Project</span><span class="p">({</span> <span class="nx">title</span><span class="o">:</span> <span class="s2">"Foo"</span> <span class="p">})</span>
<span class="nx">project</span><span class="p">.</span><span class="nx">attributes</span>
<span class="c1">// =&gt; { title: "Foo" }</span></code></pre>
<h4 id="changes"><code>changes</code></h4>
-<p>Attributes set with the <a href="#attr"><code>attr()</code></a> method are written to the <code>changes</code> intermediary object rather than directly to the <a href="#attributes"><code>attributes</code></a> object. This allows you to see any previous attribute values and enables validations &mdash; see <a href="#validate"><code>validate()</code></a> for more on validations. <code>changes</code> are committed to <a href="#attributes"><code>attributes</code></a> on successful <a href="#save"><code>save()</code></a>.</p>
+<p>Attributes set with the <a href="#attr"><code>attr()</code></a> method are written to the <code>changes</code> intermediary object rather than directly to the <a href="#attributes"><code>attributes</code></a> object. This allows you to see any previous attribute values and enables validations — see <a href="#validate"><code>validate()</code></a> for more on validations. <code>changes</code> are committed to <a href="#attributes"><code>attributes</code></a> on successful <a href="#save"><code>save()</code></a>.</p>
<pre><code><span class="kd">var</span> <span class="nx">project</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Project</span><span class="p">({</span> <span class="nx">title</span><span class="o">:</span> <span class="s2">"Foo"</span> <span class="p">})</span>
<span class="nx">project</span><span class="p">.</span><span class="nx">attributes</span> <span class="c1">// =&gt; { title: "Foo" }</span>
@@ -809,7 +808,7 @@ <h4 id="destroy"><code>destroy(callback)</code></h4>
<h4 id="errors"><code>errors</code></h4>
-<p>Returns an <a href="#api-errors"><code>Errors</code></a> object containing information about any failed validations &mdash; similar to ActiveRecord&rsquo;s Errors object. See <a href="#api-errors"><code>Errors</code></a> for more information.</p>
+<p>Returns an <a href="#api-errors"><code>Errors</code></a> object containing information about any failed validations similar to ActiveRecords Errors object. See <a href="#api-errors"><code>Errors</code></a> for more information.</p>
<h4 id="id"><code>id()</code></h4>
@@ -847,7 +846,7 @@ <h4 id="merge"><code>merge(object)</code></h4>
<h4 id="newrecord"><code>newRecord()</code></h4>
-<p>If the model doesn&rsquo;t have an id then it&rsquo;s new. This is what js-model checks when saving to decide whether it should call <a href="#create"><code>create()</code></a> or <a href="#update"><code>update()</code></a> on the persistence adapter.</p>
+<p>If the model doesnt have an id then its new. This is what js-model checks when saving to decide whether it should call <a href="#create"><code>create()</code></a> or <a href="#update"><code>update()</code></a> on the persistence adapter.</p>
<pre><code><span class="nx">egg</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Food</span><span class="p">({</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">"egg"</span> <span class="p">})</span>
<span class="nx">ham</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Food</span><span class="p">({</span> <span class="nx">id</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">name</span><span class="o">:</span> <span class="s2">"ham"</span> <span class="p">})</span>
@@ -866,12 +865,12 @@ <h4 id="save"><code>save(callback)</code></h4>
<ul>
<li>Check whether the model is <a href="#valid"><code>valid()</code></a>, if not then halt here passing the callback <code>false</code>.</li>
<li>If the model is <a href="#newrecord">new</a> then call <a href="#create"><code>create()</code></a> on the persistence adapter otherwise call <a href="#update"><code>update()</code></a>.</li>
-<li>If the persistence call is successful then <a href="#merge"><code>merge()</code></a> any <a href="#changes"><code>changes</code></a> into <a href="#attributes"><code>attributes</code></a> and <a href="#add"><code>add()</code></a> the model to the collection if it&rsquo;s new.</li>
+<li>If the persistence call is successful then <a href="#merge"><code>merge()</code></a> any <a href="#changes"><code>changes</code></a> into <a href="#attributes"><code>attributes</code></a> and <a href="#add"><code>add()</code></a> the model to the collection if its new.</li>
<li>Finally the supplied callback is called with a boolean to indicate success/failure and any further arguments the persistence adapter supplies.</li>
</ul>
-<p>If your persistence layer returns any data this will also be <a href="#merge">merged</a> into the attributes &mdash; this is how your server-assigned id gets assigned to the model when you use <a href="#rest">REST persistence</a>.</p>
+<p>If your persistence layer returns any data this will also be <a href="#merge">merged</a> into the attributes this is how your server-assigned id gets assigned to the model when you use <a href="#rest">REST persistence</a>.</p>
-<p><strong>Note:</strong> It&rsquo;s important to understand that the callback passed to <code>save()</code> may take some time to be called as it may depend on a response from your server.</p>
+<p><strong>Note:</strong> Its important to understand that the callback passed to <code>save()</code> may take some time to be called as it may depend on a response from your server.</p>
<pre><code><span class="nx">Food</span><span class="p">.</span><span class="nx">all</span><span class="p">()</span>
<span class="c1">// =&gt; [egg, ham, cheese]</span>
@@ -892,15 +891,15 @@ <h4 id="save"><code>save(callback)</code></h4>
<h4 id="uid"><code>uid</code></h4>
-<p>Automatically assigned on instantiation, this is a per-page-load-unique id &mdash; used by the <a href="#localstorage">localStorage persistence adapter</a>.</p>
+<p>Automatically assigned on instantiation, this is a per-page-load-unique id used by the <a href="#localstorage">localStorage persistence adapter</a>.</p>
<h4 id="valid"><code>valid()</code></h4>
-<p>Calls <a href="#validate"><code>validate()</code></a> and checks for the existence of any errors returning <code>true</code> or <code>false</code>. Used by <a href="#save"><code>save()</code></a> which won&rsquo;t continue if <code>valid()</code> returns <code>false</code>.</p>
+<p>Calls <a href="#validate"><code>validate()</code></a> and checks for the existence of any errors returning <code>true</code> or <code>false</code>. Used by <a href="#save"><code>save()</code></a> which wont continue if <code>valid()</code> returns <code>false</code>.</p>
<h4 id="validate"><code>validate()</code></h4>
-<p>Overwrite this method to add client-side validations to your model. This method is called on <a href="#save"><code>save()</code></a> which won&rsquo;t continue if the <a href="#errors"><code>errors</code></a> object is not empty.</p>
+<p>Overwrite this method to add client-side validations to your model. This method is called on <a href="#save"><code>save()</code></a> which wont continue if the <a href="#errors"><code>errors</code></a> object is not empty.</p>
<pre><code><span class="kd">var</span> <span class="nx">Project</span> <span class="o">=</span> <span class="nx">Model</span><span class="p">(</span><span class="s2">"project"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nx">include</span><span class="p">({</span>
@@ -921,9 +920,9 @@ <h4 id="validate"><code>validate()</code></h4>
<span class="c1">// =&gt; true</span></code></pre>
<h3 id="api-errors">Errors</h3>
-<p>Errors are used in conjunction with <a href="#validate"><code>validate()</code></a> and are modelled after ActiveModel&rsquo;s errors.</p>
+<p>Errors are used in conjunction with <a href="#validate"><code>validate()</code></a> and are modelled after ActiveModels errors.</p>
-<p><strong>Note:</strong> If you&rsquo;re using Rails 2.x you can get Rails 3-style <code>errors.to_json</code> by dropping this simple monkey patch into an initializer (<a href="http://gist.github.com/350520">Gist</a>).</p>
+<p><strong>Note:</strong> If youre using Rails 2.x you can get Rails 3-style <code>errors.to_json</code> by dropping this simple monkey patch into an initializer (<a href="http://gist.github.com/350520">Gist</a>).</p>
<pre><code><span class="k">module</span> <span class="nn">ActiveRecord</span>
<span class="k">class</span> <span class="nc">Errors</span>
@@ -998,7 +997,7 @@ <h4 id="size"><code>size()</code></h4>
<span class="c1">// =&gt; 2</span></code></pre>
<h3 id="persistence-interface">Persistence interface</h3>
-<p>Persistence adapters implement CRUD and return an object with the following interface. You probably don&rsquo;t need to know this but is documented here in case you want to implement your own.</p>
+<p>Persistence adapters implement CRUD and return an object with the following interface. You probably dont need to know this but is documented here in case you want to implement your own.</p>
<h4 id="create"><code>create(model, callback)</code></h4>
@@ -1018,7 +1017,7 @@ <h4 id="persistence-interface-destroy"><code>destroy(model, callback)</code></h4
<h4 id="read"><code>read(callback)</code></h4>
-<p>Calls the supplied callback with an array of models &mdash; models are <strong>not</strong> automatically added to the collection when calling <code>read()</code>. You probably won&rsquo;t need to use this much as this functionality is taken care of by <a href="#load"><code>load()</code></a>.</p>
+<p>Calls the supplied callback with an array of models models are <strong>not</strong> automatically added to the collection when calling <code>read()</code>. You probably wont need to use this much as this functionality is taken care of by <a href="#load"><code>load()</code></a>.</p>
<pre><code><span class="nx">Project</span><span class="p">.</span><span class="nx">persistence</span><span class="p">().</span><span class="nx">read</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">models</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// do something with the models...</span>
@@ -1034,7 +1033,7 @@ <h4 id="update"><code>update(model, callback)</code></h4>
</section>
</div>
- <footer><p>&copy; 2010-2011 <a href="http://benpickles.com/">Ben Pickles</a>. See <a href="http://github.com/benpickles/js-model/blob/master/LICENSE">LICENSE</a> for details.</p>
+ <footer><p>© 2010-2012 <a href="http://benpickles.com/">Ben Pickles</a>. See <a href="http://github.com/benpickles/js-model/blob/master/LICENSE">LICENSE</a> for details.</p>
</footer>
</body>
</html>

0 comments on commit 387f06c

Please sign in to comment.