Skip to content
This repository
Browse code

Version 0.9.2.

  • Loading branch information...
commit db6528b2b894d545620e732fdcb40a0618543526 1 parent 73bb4f1
Ben Pickles authored
6 CHANGELOG.markdown
Source Rendered
... ... @@ -1,5 +1,11 @@
1 1 # Changelog
2 2
  3 +## 0.9.2
  4 +
  5 +* Ajax DELETE sends JSON body, including AjaxSetup data if available. [Ismael Celis]
  6 +* `Model.remove()` should include removed instance in event data. [Ismael Celis]
  7 +* Call the `Model.load()` callback with the scope of the class.
  8 +
3 9 ## 0.9.1
4 10
5 11 * If defined, include jQuery.ajaxSetup data in REST parameters. [Ismael Celis]
2  VERSION
... ... @@ -1 +1 @@
1   -0.9.1
  1 +0.9.2
672 dist/js-model-0.9.2.js
... ... @@ -0,0 +1,672 @@
  1 +/* js-model JavaScript library, version 0.9.2
  2 + * (c) 2010 Ben Pickles
  3 + *
  4 + * Released under MIT license.
  5 + */
  6 +var Model = function(name, class_methods, instance_methods) {
  7 + class_methods = class_methods || {};
  8 + instance_methods = instance_methods || {};
  9 +
  10 + // The model constructor.
  11 + var model = function(attributes) {
  12 + this.attributes = attributes || {};
  13 + this.changes = {};
  14 + this.errors = new Model.Errors(this);
  15 + this.uid = [name, Model.UID.generate()].join("-")
  16 + };
  17 +
  18 + // Persistence is special, remove it from class_methods.
  19 + var persistence = class_methods.persistence
  20 + delete class_methods.persistence
  21 +
  22 + // Apply class methods and extend with any custom class methods. Make sure
  23 + // vitals are added last so they can't be overridden.
  24 + jQuery.extend(model, Model.Callbacks, Model.ClassMethods, class_methods, {
  25 + _name: name,
  26 + collection: [],
  27 +
  28 + // Convenience method to allow a simple method of chaining class methods.
  29 + chain: function(collection) {
  30 + return jQuery.extend({}, this, { collection: collection });
  31 + }
  32 + });
  33 +
  34 + // Initialise persistence with a reference to the class.
  35 + if (persistence) model.persistence = persistence(model)
  36 +
  37 + // Add default and custom instance methods.
  38 + jQuery.extend(model.prototype, Model.Callbacks, Model.InstanceMethods,
  39 + instance_methods);
  40 +
  41 + return model;
  42 +};
  43 +
  44 +Model.Callbacks = {
  45 + bind: function(event, callback) {
  46 + this.callbacks = this.callbacks || {}
  47 + this.callbacks[event] = this.callbacks[event] || [];
  48 + this.callbacks[event].push(callback);
  49 + return this;
  50 + },
  51 +
  52 + trigger: function(name, data) {
  53 + this.callbacks = this.callbacks || {}
  54 +
  55 + var callbacks = this.callbacks[name];
  56 +
  57 + if (callbacks) {
  58 + for (var i = 0; i < callbacks.length; i++) {
  59 + callbacks[i].apply(this, data || []);
  60 + }
  61 + }
  62 +
  63 + return this;
  64 + },
  65 +
  66 + unbind: function(event, callback) {
  67 + this.callbacks = this.callbacks || {}
  68 +
  69 + if (callback) {
  70 + var callbacks = this.callbacks[event] || [];
  71 +
  72 + for (var i = 0; i < callbacks.length; i++) {
  73 + if (callbacks[i] === callback) {
  74 + this.callbacks[event].splice(i, 1);
  75 + }
  76 + }
  77 + } else {
  78 + delete this.callbacks[event];
  79 + }
  80 +
  81 + return this;
  82 + }
  83 +};
  84 +
  85 +Model.ClassMethods = {
  86 + add: function() {
  87 + var added = [];
  88 + var uids = this.uids()
  89 +
  90 + for (var i = 0; i < arguments.length; i++) {
  91 + var model = arguments[i];
  92 +
  93 + if (jQuery.inArray(model, this.collection) === -1 &&
  94 + !(model.id() && this.find(model.id())) &&
  95 + jQuery.inArray(model.uid, uids) === -1)
  96 + {
  97 + this.collection.push(model);
  98 + added.push(model);
  99 + }
  100 + }
  101 +
  102 + if (added.length > 0) this.trigger("add", added);
  103 +
  104 + return this;
  105 + },
  106 +
  107 + all: function() {
  108 + return this.collection;
  109 + },
  110 +
  111 + count: function() {
  112 + return this.collection.length;
  113 + },
  114 +
  115 + detect: function(func) {
  116 + var all = this.all(),
  117 + model
  118 +
  119 + for (var i = 0, length = all.length; i < length; i++) {
  120 + model = all[i]
  121 + if (func.call(model, i)) return model
  122 + }
  123 + },
  124 +
  125 + each: function(func) {
  126 + var all = this.all()
  127 +
  128 + for (var i = 0, length = all.length; i < length; i++) {
  129 + func.call(all[i], i)
  130 + }
  131 +
  132 + return this;
  133 + },
  134 +
  135 + find: function(id) {
  136 + return this.detect(function() {
  137 + return this.id() == id;
  138 + })
  139 + },
  140 +
  141 + first: function() {
  142 + return this.all()[0]
  143 + },
  144 +
  145 + load: function(callback) {
  146 + if (this.persistence) {
  147 + var self = this
  148 +
  149 + this.persistence.read(function(models) {
  150 + for (var i = 0, length = models.length; i < length; i++) {
  151 + self.add(models[i])
  152 + }
  153 +
  154 + if (callback) callback.call(self, models)
  155 + })
  156 + }
  157 +
  158 + return this
  159 + },
  160 +
  161 + last: function() {
  162 + var all = this.all();
  163 + return all[all.length - 1]
  164 + },
  165 +
  166 + pluck: function(attribute) {
  167 + var all = this.all()
  168 + var plucked = []
  169 +
  170 + for (var i = 0, length = all.length; i < length; i++) {
  171 + plucked.push(all[i].attr(attribute))
  172 + }
  173 +
  174 + return plucked
  175 + },
  176 +
  177 + remove: function(model) {
  178 + var index
  179 +
  180 + for (var i = 0, length = this.collection.length; i < length; i++) {
  181 + if (this.collection[i] === model) {
  182 + index = i
  183 + break
  184 + }
  185 + }
  186 +
  187 + if (index != undefined) {
  188 + this.collection.splice(index, 1);
  189 + this.trigger("remove", [model]);
  190 + return true;
  191 + } else {
  192 + return false;
  193 + }
  194 + },
  195 +
  196 + reverse: function() {
  197 + return this.chain(this.all().reverse())
  198 + },
  199 +
  200 + select: function(func) {
  201 + var all = this.all(),
  202 + selected = [],
  203 + model
  204 +
  205 + for (var i = 0, length = all.length; i < length; i++) {
  206 + model = all[i]
  207 + if (func.call(model, i)) selected.push(model)
  208 + }
  209 +
  210 + return this.chain(selected);
  211 + },
  212 +
  213 + sort: function(func) {
  214 + var sorted = this.all().slice().sort(func)
  215 + return this.chain(sorted);
  216 + },
  217 +
  218 + sortBy: function(attribute_or_func) {
  219 + var is_func = jQuery.isFunction(attribute_or_func)
  220 + var extract = function(model) {
  221 + return attribute_or_func.call(model)
  222 + }
  223 +
  224 + return this.sort(function(a, b) {
  225 + var a_attr = is_func ? extract(a) : a.attr(attribute_or_func)
  226 + var b_attr = is_func ? extract(b) : b.attr(attribute_or_func)
  227 +
  228 + if (a_attr < b_attr) {
  229 + return -1
  230 + } else if (a_attr > b_attr) {
  231 + return 1
  232 + } else {
  233 + return 0
  234 + }
  235 + })
  236 + },
  237 +
  238 + uids: function() {
  239 + var all = this.all()
  240 + var uids = []
  241 +
  242 + for (var i = 0, length = all.length; i < length; i++) {
  243 + uids.push(all[i].uid)
  244 + }
  245 +
  246 + return uids
  247 + }
  248 +};
  249 +
  250 +Model.Errors = function(model) {
  251 + this.errors = {};
  252 + this.model = model;
  253 +};
  254 +
  255 +Model.Errors.prototype = {
  256 + add: function(attribute, message) {
  257 + if (!this.errors[attribute]) this.errors[attribute] = [];
  258 + this.errors[attribute].push(message);
  259 + return this
  260 + },
  261 +
  262 + all: function() {
  263 + return this.errors;
  264 + },
  265 +
  266 + clear: function() {
  267 + this.errors = {};
  268 + return this
  269 + },
  270 +
  271 + each: function(func) {
  272 + for (var attribute in this.errors) {
  273 + for (var i = 0; i < this.errors[attribute].length; i++) {
  274 + func.call(this, attribute, this.errors[attribute][i]);
  275 + }
  276 + }
  277 + return this
  278 + },
  279 +
  280 + on: function(attribute) {
  281 + return this.errors[attribute] || [];
  282 + },
  283 +
  284 + size: function() {
  285 + var count = 0;
  286 + this.each(function() { count++; });
  287 + return count;
  288 + }
  289 +};
  290 +
  291 +Model.InstanceMethods = {
  292 + attr: function(name, value) {
  293 + if (arguments.length === 0) {
  294 + // Combined attributes/changes object.
  295 + return jQuery.extend({}, this.attributes, this.changes);
  296 + } else if (arguments.length === 2) {
  297 + // Don't write to attributes yet, store in changes for now.
  298 + if (this.attributes[name] === value) {
  299 + // Clean up any stale changes.
  300 + delete this.changes[name];
  301 + } else {
  302 + this.changes[name] = value;
  303 + }
  304 + return this;
  305 + } else if (typeof name === "object") {
  306 + // Mass-assign attributes.
  307 + for (var key in name) {
  308 + this.attr(key, name[key]);
  309 + }
  310 + return this;
  311 + } else {
  312 + // Changes take precedent over attributes.
  313 + return (name in this.changes) ?
  314 + this.changes[name] :
  315 + this.attributes[name];
  316 + }
  317 + },
  318 +
  319 + callPersistMethod: function(method, callback) {
  320 + var self = this;
  321 +
  322 + // Automatically manage adding and removing from the model's Collection.
  323 + var manageCollection = function() {
  324 + if (method === "create") {
  325 + self.constructor.add(self);
  326 + } else if (method === "destroy") {
  327 + self.constructor.remove(self)
  328 + }
  329 + };
  330 +
  331 + // Wrap the existing callback in this function so we always manage the
  332 + // collection and trigger events from here rather than relying on the
  333 + // persistence adapter to do it for us. The persistence adapter is
  334 + // only required to execute the callback with a single argument - a
  335 + // boolean to indicate whether the call was a success - though any
  336 + // other arguments will also be forwarded to the original callback.
  337 + var wrappedCallback = function(success) {
  338 + if (success) {
  339 + // Merge any changes into attributes and clear changes.
  340 + self.merge(self.changes).reset();
  341 +
  342 + // Add/remove from collection if persist was successful.
  343 + manageCollection();
  344 +
  345 + // Trigger the event before executing the callback.
  346 + self.trigger(method);
  347 + }
  348 +
  349 + // Store the return value of the callback.
  350 + var value;
  351 +
  352 + // Run the supplied callback.
  353 + if (callback) value = callback.apply(self, arguments);
  354 +
  355 + return value;
  356 + };
  357 +
  358 + if (this.constructor.persistence) {
  359 + this.constructor.persistence[method](this, wrappedCallback);
  360 + } else {
  361 + wrappedCallback.call(this, true);
  362 + }
  363 + },
  364 +
  365 + destroy: function(callback) {
  366 + this.callPersistMethod("destroy", callback);
  367 + return this;
  368 + },
  369 +
  370 + id: function() {
  371 + return this.attributes.id
  372 + },
  373 +
  374 + merge: function(attributes) {
  375 + jQuery.extend(this.attributes, attributes);
  376 + return this;
  377 + },
  378 +
  379 + newRecord: function() {
  380 + return this.id() === undefined
  381 + },
  382 +
  383 + reset: function() {
  384 + this.errors.clear();
  385 + this.changes = {};
  386 + return this;
  387 + },
  388 +
  389 + save: function(callback) {
  390 + if (this.valid()) {
  391 + var method = this.newRecord() ? "create" : "update";
  392 + this.callPersistMethod(method, callback);
  393 + } else if (callback) {
  394 + callback(false);
  395 + }
  396 +
  397 + return this;
  398 + },
  399 +
  400 + valid: function() {
  401 + this.errors.clear();
  402 + this.validate();
  403 + return this.errors.size() === 0;
  404 + },
  405 +
  406 + validate: function() {
  407 + return this;
  408 + }
  409 +};
  410 +
  411 +Model.localStorage = function() {
  412 + if (!window.localStorage) {
  413 + return function() {
  414 + return {
  415 + create: function(model, callback) {
  416 + callback(true)
  417 + },
  418 +
  419 + destroy: function(model, callback) {
  420 + callback(true)
  421 + },
  422 +
  423 + read: function(callback) {
  424 + callback([])
  425 + },
  426 +
  427 + update: function(model, callback) {
  428 + callback(true)
  429 + }
  430 + }
  431 + }
  432 + }
  433 +
  434 + return function(klass) {
  435 + var collection_uid = [klass._name, "collection"].join("-")
  436 + var readIndex = function() {
  437 + var data = localStorage[collection_uid]
  438 + return data ? JSON.parse(data) : []
  439 + }
  440 + var writeIndex = function(uids) {
  441 + localStorage.setItem(collection_uid, JSON.stringify(uids))
  442 + }
  443 + var addToIndex = function(uid) {
  444 + var uids = readIndex()
  445 +
  446 + if (jQuery.inArray(uid, uids) === -1) {
  447 + uids.push(uid)
  448 + writeIndex(uids)
  449 + }
  450 + }
  451 + var removeFromIndex = function(uid) {
  452 + var uids = readIndex()
  453 + var index = jQuery.inArray(uid, uids)
  454 +
  455 + if (index > -1) {
  456 + uids.splice(index, 1)
  457 + writeIndex(uids)
  458 + }
  459 + }
  460 + var store = function(model) {
  461 + var uid = model.uid,
  462 + data = JSON.stringify(model.attr())
  463 + localStorage.setItem(uid, data)
  464 + addToIndex(uid)
  465 + }
  466 +
  467 + return {
  468 + create: function(model, callback) {
  469 + store(model)
  470 + callback(true)
  471 + },
  472 +
  473 + destroy: function(model, callback) {
  474 + localStorage.removeItem(model.uid)
  475 + removeFromIndex(model.uid)
  476 + callback(true)
  477 + },
  478 +
  479 + read: function(callback) {
  480 + if (!callback) return false
  481 +
  482 + var uids = readIndex()
  483 + var models = []
  484 + var attributes, model, uid
  485 +
  486 + for (var i = 0, length = uids.length; i < length; i++) {
  487 + uid = uids[i]
  488 + attributes = JSON.parse(localStorage[uid])
  489 + model = new klass(attributes)
  490 + model.uid = uid
  491 + models.push(model)
  492 + }
  493 +
  494 + callback(models)
  495 + },
  496 +
  497 + update: function(model, callback) {
  498 + store(model)
  499 + callback(true)
  500 + }
  501 + }
  502 + }
  503 +}
  504 +
  505 +Model.Log = function() {
  506 + if (window.console) window.console.log.apply(window.console, arguments);
  507 +};
  508 +
  509 +Model.REST = function(resource, methods) {
  510 + var PARAM_NAME_MATCHER = /:([\w\d]+)/g;
  511 + var resource_param_names = (function() {
  512 + var resource_param_names = []
  513 + var param_name
  514 +
  515 + while ((param_name = PARAM_NAME_MATCHER.exec(resource)) !== null) {
  516 + resource_param_names.push(param_name[1])
  517 + }
  518 +
  519 + return resource_param_names
  520 + })()
  521 +
  522 + var rest_persistence = jQuery.extend({
  523 + path: function(model) {
  524 + var path = resource;
  525 + $.each(resource_param_names, function(i, param) {
  526 + path = path.replace(":" + param, model.attributes[param]);
  527 + });
  528 + return path;
  529 + },
  530 +
  531 + create: function(model, callback) {
  532 + return this.xhr('POST', this.create_path(model), model, callback);
  533 + },
  534 +
  535 + create_path: function(model) {
  536 + return this.path(model);
  537 + },
  538 +
  539 + destroy: function(model, callback) {
  540 + return this.xhr('DELETE', this.destroy_path(model), model, callback);
  541 + },
  542 +
  543 + destroy_path: function(model) {
  544 + return this.update_path(model);
  545 + },
  546 +
  547 + params: function(model) {
  548 + var params;
  549 + if (model) {
  550 + var attributes = model.attr();
  551 + delete attributes.id;
  552 + params = {};
  553 + params[model.constructor._name.toLowerCase()] = attributes;
  554 + } else {
  555 + params = null;
  556 + }
  557 + if(jQuery.ajaxSettings.data){
  558 + params = jQuery.extend({}, jQuery.ajaxSettings.data, params)
  559 + }
  560 + return JSON.stringify(params)
  561 + },
  562 +
  563 + read: function(callback) {
  564 + var klass = this.klass
  565 +
  566 + return this.xhr("GET", this.read_path(), null, function(success, xhr, data) {
  567 + data = jQuery.makeArray(data)
  568 + var models = []
  569 +
  570 + for (var i = 0, length = data.length; i < length; i++) {
  571 + models.push(new klass(data[i]))
  572 + }
  573 +
  574 + callback(models)
  575 + })
  576 + },
  577 +
  578 + read_path: function() {
  579 + return resource
  580 + },
  581 +
  582 + update: function(model, callback) {
  583 + return this.xhr('PUT', this.update_path(model), model, callback);
  584 + },
  585 +
  586 + update_path: function(model) {
  587 + return [this.path(model), model.id()].join('/');
  588 + },
  589 +
  590 + xhr: function(method, url, model, callback) {
  591 + var self = this;
  592 + var data = method == 'GET' ? undefined : this.params(model);
  593 +
  594 + return jQuery.ajax({
  595 + type: method,
  596 + url: url,
  597 + contentType: "application/json",
  598 + dataType: "json",
  599 + data: data,
  600 + dataFilter: function(data, type) {
  601 + return /\S/.test(data) ? data : undefined;
  602 + },
  603 + complete: function(xhr, textStatus) {
  604 + self.xhrComplete(xhr, textStatus, model, callback)
  605 + }
  606 + });
  607 + },
  608 +
  609 + xhrComplete: function(xhr, textStatus, model, callback) {
  610 + // Allow custom handlers to be defined per-HTTP status code.
  611 + var handler = Model.REST["handle" + xhr.status]
  612 + if (handler) handler.call(this, xhr, textStatus, model)
  613 +
  614 + var success = textStatus === "success"
  615 + var data = Model.REST.parseResponseData(xhr)
  616 +
  617 + // Remote data is the definitive source, update model.
  618 + if (success && model && data) model.attr(data)
  619 +
  620 + if (callback) callback.call(model, success, xhr, data)
  621 + }
  622 + }, methods)
  623 +
  624 + return function(klass) {
  625 + rest_persistence.klass = klass
  626 + return rest_persistence
  627 + }
  628 +};
  629 +
  630 +// TODO: Remove in v1 if it ever gets there.
  631 +Model.RestPersistence = Model.REST
  632 +
  633 +// Rails' preferred failed validation response code, assume the response
  634 +// contains errors and replace current model errors with them.
  635 +Model.REST.handle422 = function(xhr, textStatus, model) {
  636 + var data = Model.REST.parseResponseData(xhr);
  637 +
  638 + if (data) {
  639 + model.errors.clear()
  640 +
  641 + for (var attribute in data) {
  642 + for (var i = 0; i < data[attribute].length; i++) {
  643 + model.errors.add(attribute, data[attribute][i])
  644 + }
  645 + }
  646 + }
  647 +}
  648 +
  649 +Model.REST.parseResponseData = function(xhr) {
  650 + try {
  651 + return /\S/.test(xhr.responseText) ?
  652 + jQuery.parseJSON(xhr.responseText) :
  653 + undefined;
  654 + } catch(e) {
  655 + Model.Log(e);
  656 + }
  657 +}
  658 +
  659 +Model.UID = {
  660 + counter: 0,
  661 +
  662 + generate: function() {
  663 + return [new Date().valueOf(), this.counter++].join("-")
  664 + },
  665 +
  666 + reset: function() {
  667 + this.counter = 0
  668 + return this
  669 + }
  670 +}
  671 +
  672 +Model.VERSION = "0.9.2"
21 dist/js-model-0.9.2.min.js
... ... @@ -0,0 +1,21 @@
  1 +/* js-model JavaScript library, version 0.9.2
  2 + * (c) 2010 Ben Pickles
  3 + *
  4 + * Released under MIT license.
  5 + */
  6 +var Model=function(a,c,b){c=c||{};b=b||{};var d=function(e){this.attributes=e||{};this.changes={};this.errors=new Model.Errors(this);this.uid=[a,Model.UID.generate()].join("-")},i=c.persistence;delete c.persistence;jQuery.extend(d,Model.Callbacks,Model.ClassMethods,c,{_name:a,collection:[],chain:function(e){return jQuery.extend({},this,{collection:e})}});if(i)d.persistence=i(d);jQuery.extend(d.prototype,Model.Callbacks,Model.InstanceMethods,b);return d};
  7 +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||{};if(a=this.callbacks[a])for(var b=0;b<a.length;b++)a[b].apply(this,c||[]);return this},unbind:function(a,c){this.callbacks=this.callbacks||{};if(c)for(var b=this.callbacks[a]||[],d=0;d<b.length;d++)b[d]===c&&this.callbacks[a].splice(d,1);else delete this.callbacks[a];return this}};
  8 +Model.ClassMethods={add:function(){for(var a=[],c=this.uids(),b=0;b<arguments.length;b++){var d=arguments[b];if(jQuery.inArray(d,this.collection)===-1&&!(d.id()&&this.find(d.id()))&&jQuery.inArray(d.uid,c)===-1){this.collection.push(d);a.push(d)}}a.length>0&&this.trigger("add",a);return this},all:function(){return this.collection},count:function(){return this.collection.length},detect:function(a){for(var c=this.all(),b,d=0,i=c.length;d<i;d++){b=c[d];if(a.call(b,d))return b}},each:function(a){for(var c=
  9 +this.all(),b=0,d=c.length;b<d;b++)a.call(c[b],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 d=0,i=b.length;d<i;d++)c.add(b[d]);a&&a.call(c,b)})}return this},last:function(){var a=this.all();return a[a.length-1]},pluck:function(a){for(var c=this.all(),b=[],d=0,i=c.length;d<i;d++)b.push(c[d].attr(a));return b},remove:function(a){for(var c,
  10 +b=0,d=this.collection.length;b<d;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){for(var c=this.all(),b=[],d,i=0,e=c.length;i<e;i++){d=c[i];a.call(d,i)&&b.push(d)}return this.chain(b)},sort:function(a){return this.chain(this.all().slice().sort(a))},sortBy:function(a){var c=jQuery.isFunction(a),b=function(d){return a.call(d)};
  11 +return this.sort(function(d,i){d=c?b(d):d.attr(a);i=c?b(i):i.attr(a);return d<i?-1:d>i?1:0})},uids:function(){for(var a=this.all(),c=[],b=0,d=a.length;b<d;b++)c.push(a[b].uid);return c}};Model.Errors=function(a){this.errors={};this.model=a};
  12 +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}};
  13 +Model.InstanceMethods={attr:function(a,c){if(arguments.length===0)return jQuery.extend({},this.attributes,this.changes);else if(arguments.length===2){if(this.attributes[a]===c)delete this.changes[a];else this.changes[a]=c;return this}else if(typeof a==="object"){for(var b in a)this.attr(b,a[b]);return this}else return a in this.changes?this.changes[a]:this.attributes[a]},callPersistMethod:function(a,c){var b=this,d=function(){if(a==="create")b.constructor.add(b);else a==="destroy"&&b.constructor.remove(b)},
  14 +i=function(e){if(e){b.merge(b.changes).reset();d();b.trigger(a)}var g;if(c)g=c.apply(b,arguments);return g};this.constructor.persistence?this.constructor.persistence[a](this,i):i.call(this,true)},destroy:function(a){this.callPersistMethod("destroy",a);return this},id:function(){return this.attributes.id},merge:function(a){jQuery.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()?
  15 +"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}};
  16 +Model.localStorage=function(){if(!window.localStorage)return function(){return{create:function(a,c){c(true)},destroy:function(a,c){c(true)},read:function(a){a([])},update:function(a,c){c(true)}}};return function(a){var c=[a._name,"collection"].join("-"),b=function(){var f=localStorage[c];return f?JSON.parse(f):[]},d=function(f){localStorage.setItem(c,JSON.stringify(f))},i=function(f){var h=b();if(jQuery.inArray(f,h)===-1){h.push(f);d(h)}},e=function(f){var h=b();f=jQuery.inArray(f,h);if(f>-1){h.splice(f,
  17 +1);d(h)}},g=function(f){var h=f.uid;f=JSON.stringify(f.attr());localStorage.setItem(h,f);i(h)};return{create:function(f,h){g(f);h(true)},destroy:function(f,h){localStorage.removeItem(f.uid);e(f.uid);h(true)},read:function(f){if(!f)return false;for(var h=b(),j=[],k,l,m=0,n=h.length;m<n;m++){l=h[m];k=JSON.parse(localStorage[l]);k=new a(k);k.uid=l;j.push(k)}f(j)},update:function(f,h){g(f);h(true)}}}};Model.Log=function(){window.console&&window.console.log.apply(window.console,arguments)};
  18 +Model.REST=function(a,c){var b=/:([\w\d]+)/g,d=function(){for(var e=[],g;(g=b.exec(a))!==null;)e.push(g[1]);return e}(),i=jQuery.extend({path:function(e){var g=a;$.each(d,function(f,h){g=g.replace(":"+h,e.attributes[h])});return g},create:function(e,g){return this.xhr("POST",this.create_path(e),e,g)},create_path:function(e){return this.path(e)},destroy:function(e,g){return this.xhr("DELETE",this.destroy_path(e),e,g)},destroy_path:function(e){return this.update_path(e)},params:function(e){var g;if(e){var f=
  19 +e.attr();delete f.id;g={};g[e.constructor._name.toLowerCase()]=f}else g=null;if(jQuery.ajaxSettings.data)g=jQuery.extend({},jQuery.ajaxSettings.data,g);return JSON.stringify(g)},read:function(e){var g=this.klass;return this.xhr("GET",this.read_path(),null,function(f,h,j){j=jQuery.makeArray(j);f=[];h=0;for(var k=j.length;h<k;h++)f.push(new g(j[h]));e(f)})},read_path:function(){return a},update:function(e,g){return this.xhr("PUT",this.update_path(e),e,g)},update_path:function(e){return[this.path(e),
  20 +e.id()].join("/")},xhr:function(e,g,f,h){var j=this,k=e=="GET"?undefined:this.params(f);return jQuery.ajax({type:e,url:g,contentType:"application/json",dataType:"json",data:k,dataFilter:function(l){return/\S/.test(l)?l:undefined},complete:function(l,m){j.xhrComplete(l,m,f,h)}})},xhrComplete:function(e,g,f,h){var j=Model.REST["handle"+e.status];j&&j.call(this,e,g,f);g=g==="success";j=Model.REST.parseResponseData(e);g&&f&&j&&f.attr(j);h&&h.call(f,g,e,j)}},c);return function(e){i.klass=e;return i}};
  21 +Model.RestPersistence=Model.REST;Model.REST.handle422=function(a,c,b){if(a=Model.REST.parseResponseData(a)){b.errors.clear();for(var d in a)for(c=0;c<a[d].length;c++)b.errors.add(d,a[d][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.VERSION="0.9.2";
6 index.html
@@ -5,16 +5,16 @@
5 5 <link href="docs/style.css" rel="stylesheet">
6 6 </head>
7 7 <body>
8   - <h1>js-model (0.9.1)</h1>
  8 + <h1>js-model (0.9.2)</h1>
9 9
10 10 <p class="intro">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>
11 11
12 12 <dl>
13 13 <dt>Download</dt>
14 14 <dd>
15   -<a href="dist/js-model-0.9.1.min.js">js-model-0.9.1.min.js</a> (7.5Kb)</dd>
  15 +<a href="dist/js-model-0.9.2.min.js">js-model-0.9.2.min.js</a> (7.5Kb)</dd>
16 16 <dd>
17   -<a href="dist/js-model-0.9.1.js">js-model-0.9.1.js</a> (15.9Kb)</dd>
  17 +<a href="dist/js-model-0.9.2.js">js-model-0.9.2.js</a> (15.9Kb)</dd>
18 18 <dd>Also available on <a href="http://cachedcommons.org/">Cached Commons</a>
19 19 </dd>
20 20

0 comments on commit db6528b

Please sign in to comment.
Something went wrong with that request. Please try again.