1 | (function() {
|
2 | var Events, Model, Module, createObject, isArray, isBlank, makeArray,
|
3 | __hasProp = {}.hasOwnProperty,
|
4 | __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
|
5 | __slice = [].slice;
|
6 |
|
7 | Events = require("./events");
|
8 |
|
9 | Module = require("./module");
|
10 |
|
11 | Model = (function(_super) {
|
12 | __extends(Model, _super);
|
13 |
|
14 | Model.extend(Events);
|
15 |
|
16 | Model.records = [];
|
17 |
|
18 | Model.irecords = {};
|
19 |
|
20 | Model.attributes = [];
|
21 |
|
22 | Model.configure = function() {
|
23 | var attributes, name;
|
24 | name = arguments[0], attributes = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
|
25 | this.className = name;
|
26 | this.deleteAll();
|
27 | if (attributes.length) {
|
28 | this.attributes = attributes;
|
29 | }
|
30 | this.attributes && (this.attributes = makeArray(this.attributes));
|
31 | this.attributes || (this.attributes = []);
|
32 | this.unbind();
|
33 | return this;
|
34 | };
|
35 |
|
36 | Model.toString = function() {
|
37 | return "" + this.className + "(" + (this.attributes.join(", ")) + ")";
|
38 | };
|
39 |
|
40 | Model.find = function(id) {
|
41 | var record;
|
42 | record = this.exists(id);
|
43 | if (!record) {
|
44 | throw new Error("\"" + this.className + "\" model could not find a record for the ID \"" + id + "\"");
|
45 | }
|
46 | return record;
|
47 | };
|
48 |
|
49 | Model.exists = function(id) {
|
50 | var _ref;
|
51 | return (_ref = this.irecords[id]) != null ? _ref.clone() : void 0;
|
52 | };
|
53 |
|
54 | Model.addRecord = function(record) {
|
55 | if (record.id && this.irecords[record.id]) {
|
56 | this.irecords[record.id].remove();
|
57 | }
|
58 | record.id || (record.id = record.cid);
|
59 | this.records.push(record);
|
60 | this.irecords[record.id] = record;
|
61 | return this.irecords[record.cid] = record;
|
62 | };
|
63 |
|
64 | Model.refresh = function(values, options) {
|
65 | var record, records, result, _i, _len;
|
66 | if (options == null) {
|
67 | options = {};
|
68 | }
|
69 | if (options.clear) {
|
70 | this.deleteAll();
|
71 | }
|
72 | records = this.fromJSON(values);
|
73 | if (!isArray(records)) {
|
74 | records = [records];
|
75 | }
|
76 | for (_i = 0, _len = records.length; _i < _len; _i++) {
|
77 | record = records[_i];
|
78 | this.addRecord(record);
|
79 | }
|
80 | this.sort();
|
81 | result = this.cloneArray(records);
|
82 | this.trigger('refresh', result, options);
|
83 | return result;
|
84 | };
|
85 |
|
86 | Model.select = function(callback) {
|
87 | var record, _i, _len, _ref, _results;
|
88 | _ref = this.records;
|
89 | _results = [];
|
90 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
91 | record = _ref[_i];
|
92 | if (callback(record)) {
|
93 | _results.push(record.clone());
|
94 | }
|
95 | }
|
96 | return _results;
|
97 | };
|
98 |
|
99 | Model.findByAttribute = function(name, value) {
|
100 | var record, _i, _len, _ref;
|
101 | _ref = this.records;
|
102 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
103 | record = _ref[_i];
|
104 | if (record[name] === value) {
|
105 | return record.clone();
|
106 | }
|
107 | }
|
108 | return null;
|
109 | };
|
110 |
|
111 | Model.findAllByAttribute = function(name, value) {
|
112 | return this.select(function(item) {
|
113 | return item[name] === value;
|
114 | });
|
115 | };
|
116 |
|
117 | Model.each = function(callback) {
|
118 | var record, _i, _len, _ref, _results;
|
119 | _ref = this.records;
|
120 | _results = [];
|
121 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
122 | record = _ref[_i];
|
123 | _results.push(callback(record.clone()));
|
124 | }
|
125 | return _results;
|
126 | };
|
127 |
|
128 | Model.all = function() {
|
129 | return this.cloneArray(this.records);
|
130 | };
|
131 |
|
132 | Model.first = function() {
|
133 | var _ref;
|
134 | return (_ref = this.records[0]) != null ? _ref.clone() : void 0;
|
135 | };
|
136 |
|
137 | Model.last = function() {
|
138 | var _ref;
|
139 | return (_ref = this.records[this.records.length - 1]) != null ? _ref.clone() : void 0;
|
140 | };
|
141 |
|
142 | Model.count = function() {
|
143 | return this.records.length;
|
144 | };
|
145 |
|
146 | Model.deleteAll = function() {
|
147 | this.records = [];
|
148 | return this.irecords = {};
|
149 | };
|
150 |
|
151 | Model.destroyAll = function(options) {
|
152 | var record, _i, _len, _ref, _results;
|
153 | _ref = this.records;
|
154 | _results = [];
|
155 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
156 | record = _ref[_i];
|
157 | _results.push(record.destroy(options));
|
158 | }
|
159 | return _results;
|
160 | };
|
161 |
|
162 | Model.update = function(id, atts, options) {
|
163 | return this.find(id).updateAttributes(atts, options);
|
164 | };
|
165 |
|
166 | Model.create = function(atts, options) {
|
167 | var record;
|
168 | record = new this(atts);
|
169 | return record.save(options);
|
170 | };
|
171 |
|
172 | Model.destroy = function(id, options) {
|
173 | return this.find(id).destroy(options);
|
174 | };
|
175 |
|
176 | Model.change = function(callbackOrParams) {
|
177 | if (typeof callbackOrParams === 'function') {
|
178 | return this.bind('change', callbackOrParams);
|
179 | } else {
|
180 | return this.trigger.apply(this, ['change'].concat(__slice.call(arguments)));
|
181 | }
|
182 | };
|
183 |
|
184 | Model.fetch = function(callbackOrParams) {
|
185 | if (typeof callbackOrParams === 'function') {
|
186 | return this.bind('fetch', callbackOrParams);
|
187 | } else {
|
188 | return this.trigger.apply(this, ['fetch'].concat(__slice.call(arguments)));
|
189 | }
|
190 | };
|
191 |
|
192 | Model.toJSON = function() {
|
193 | return this.records;
|
194 | };
|
195 |
|
196 | Model.fromJSON = function(objects) {
|
197 | var value, _i, _len, _results;
|
198 | if (!objects) {
|
199 | return;
|
200 | }
|
201 | if (typeof objects === 'string') {
|
202 | objects.replace(/\Id/g, 'id');
|
203 | objects = JSON.parse(objects);
|
204 | }
|
205 | if (isArray(objects)) {
|
206 | _results = [];
|
207 | for (_i = 0, _len = objects.length; _i < _len; _i++) {
|
208 | value = objects[_i];
|
209 | if (value.Id) {
|
210 | value.id = value.Id;
|
211 | }
|
212 | _results.push(new this(value));
|
213 | }
|
214 | return _results;
|
215 | } else {
|
216 | if (objects.Id) {
|
217 | objects.id = objects.Id;
|
218 | }
|
219 | return new this(objects);
|
220 | }
|
221 | };
|
222 |
|
223 | Model.fromForm = function() {
|
224 | var _ref;
|
225 | return (_ref = new this).fromForm.apply(_ref, arguments);
|
226 | };
|
227 |
|
228 | Model.sort = function() {
|
229 | if (this.comparator) {
|
230 | this.records.sort(this.comparator);
|
231 | }
|
232 | return this;
|
233 | };
|
234 |
|
235 | Model.cloneArray = function(array) {
|
236 | var value, _i, _len, _results;
|
237 | _results = [];
|
238 | for (_i = 0, _len = array.length; _i < _len; _i++) {
|
239 | value = array[_i];
|
240 | _results.push(value.clone());
|
241 | }
|
242 | return _results;
|
243 | };
|
244 |
|
245 | Model.idCounter = 0;
|
246 |
|
247 | Model.uid = function(prefix) {
|
248 | var uid;
|
249 | if (prefix == null) {
|
250 | prefix = '';
|
251 | }
|
252 | uid = prefix + this.idCounter++;
|
253 | if (this.exists(uid)) {
|
254 | uid = this.uid(prefix);
|
255 | }
|
256 | return uid;
|
257 | };
|
258 |
|
259 | function Model(atts) {
|
260 | Model.__super__.constructor.apply(this, arguments);
|
261 | if (atts) {
|
262 | this.load(atts);
|
263 | }
|
264 | this.cid = (atts != null ? atts.cid : void 0) || this.constructor.uid('c-');
|
265 | }
|
266 |
|
267 | Model.prototype.isNew = function() {
|
268 | return !this.exists();
|
269 | };
|
270 |
|
271 | Model.prototype.isValid = function() {
|
272 | return !this.validate();
|
273 | };
|
274 |
|
275 | Model.prototype.validate = function() {};
|
276 |
|
277 | Model.prototype.load = function(atts) {
|
278 | var key, value;
|
279 | if (atts.id) {
|
280 | this.id = atts.id;
|
281 | }
|
282 | for (key in atts) {
|
283 | value = atts[key];
|
284 | if (atts.hasOwnProperty(key) && typeof this[key] === 'function') {
|
285 | this[key](value);
|
286 | } else {
|
287 | this[key] = value;
|
288 | }
|
289 | }
|
290 | return this;
|
291 | };
|
292 |
|
293 | Model.prototype.get = function(attr) {
|
294 | return this[attr];
|
295 | };
|
296 |
|
297 | Model.prototype.set = function(attr, value) {
|
298 | return this[attr] = value;
|
299 | };
|
300 |
|
301 | Model.prototype.attributes = function() {
|
302 | var key, result, _i, _len, _ref;
|
303 | result = {};
|
304 | _ref = this.constructor.attributes;
|
305 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
306 | key = _ref[_i];
|
307 | if (key in this) {
|
308 | if (typeof this[key] === 'function') {
|
309 | result[key] = this[key]();
|
310 | } else {
|
311 | result[key] = this[key];
|
312 | }
|
313 | }
|
314 | }
|
315 | if (this.id) {
|
316 | result.id = this.id;
|
317 | }
|
318 | return result;
|
319 | };
|
320 |
|
321 | Model.prototype.eql = function(rec) {
|
322 | return !!(rec && rec.constructor === this.constructor && (rec.cid === this.cid) || (rec.id && rec.id === this.id));
|
323 | };
|
324 |
|
325 | Model.prototype.save = function(options) {
|
326 | var error, record;
|
327 | if (options == null) {
|
328 | options = {};
|
329 | }
|
330 | if (options.validate !== false) {
|
331 | error = this.validate();
|
332 | if (error) {
|
333 | this.trigger('error', error);
|
334 | return false;
|
335 | }
|
336 | }
|
337 | this.trigger('beforeSave', options);
|
338 | record = this.isNew() ? this.create(options) : this.update(options);
|
339 | this.stripCloneAttrs();
|
340 | this.trigger('save', options);
|
341 | return record;
|
342 | };
|
343 |
|
344 | Model.prototype.stripCloneAttrs = function() {
|
345 | var key, value;
|
346 | if (this.hasOwnProperty('cid')) {
|
347 | return;
|
348 | }
|
349 | for (key in this) {
|
350 | if (!__hasProp.call(this, key)) continue;
|
351 | value = this[key];
|
352 | if (this.constructor.attributes.indexOf(key) > -1) {
|
353 | delete this[key];
|
354 | }
|
355 | }
|
356 | return this;
|
357 | };
|
358 |
|
359 | Model.prototype.updateAttribute = function(name, value, options) {
|
360 | var atts;
|
361 | atts = {};
|
362 | atts[name] = value;
|
363 | return this.updateAttributes(atts, options);
|
364 | };
|
365 |
|
366 | Model.prototype.updateAttributes = function(atts, options) {
|
367 | this.load(atts);
|
368 | return this.save(options);
|
369 | };
|
370 |
|
371 | Model.prototype.changeID = function(id) {
|
372 | var records;
|
373 | if (id === this.id) {
|
374 | return;
|
375 | }
|
376 | records = this.constructor.irecords;
|
377 | records[id] = records[this.id];
|
378 | delete records[this.id];
|
379 | this.id = id;
|
380 | return this.save();
|
381 | };
|
382 |
|
383 | Model.prototype.remove = function() {
|
384 | var i, record, records, _i, _len;
|
385 | records = this.constructor.records.slice(0);
|
386 | for (i = _i = 0, _len = records.length; _i < _len; i = ++_i) {
|
387 | record = records[i];
|
388 | if (!(this.eql(record))) {
|
389 | continue;
|
390 | }
|
391 | records.splice(i, 1);
|
392 | break;
|
393 | }
|
394 | this.constructor.records = records;
|
395 | delete this.constructor.irecords[this.id];
|
396 | return delete this.constructor.irecords[this.cid];
|
397 | };
|
398 |
|
399 | Model.prototype.destroy = function(options) {
|
400 | if (options == null) {
|
401 | options = {};
|
402 | }
|
403 | this.trigger('beforeDestroy', options);
|
404 | this.remove();
|
405 | this.destroyed = true;
|
406 | this.trigger('destroy', options);
|
407 | this.trigger('change', 'destroy', options);
|
408 | if (this.listeningTo) {
|
409 | this.stopListening();
|
410 | }
|
411 | this.unbind();
|
412 | return this;
|
413 | };
|
414 |
|
415 | Model.prototype.dup = function(newRecord) {
|
416 | var atts;
|
417 | if (newRecord == null) {
|
418 | newRecord = true;
|
419 | }
|
420 | atts = this.attributes();
|
421 | if (newRecord) {
|
422 | delete atts.id;
|
423 | } else {
|
424 | atts.cid = this.cid;
|
425 | }
|
426 | return new this.constructor(atts);
|
427 | };
|
428 |
|
429 | Model.prototype.clone = function() {
|
430 | return createObject(this);
|
431 | };
|
432 |
|
433 | Model.prototype.reload = function() {
|
434 | var original;
|
435 | if (this.isNew()) {
|
436 | return this;
|
437 | }
|
438 | original = this.constructor.find(this.id);
|
439 | this.load(original.attributes());
|
440 | return original;
|
441 | };
|
442 |
|
443 | Model.prototype.refresh = function(data) {
|
444 | var root;
|
445 | root = this.constructor.irecords[this.id];
|
446 | root.load(data);
|
447 | this.trigger('refresh');
|
448 | return this;
|
449 | };
|
450 |
|
451 | Model.prototype.toJSON = function() {
|
452 | return this.attributes();
|
453 | };
|
454 |
|
455 | Model.prototype.toString = function() {
|
456 | return "<" + this.constructor.className + " (" + (JSON.stringify(this)) + ")>";
|
457 | };
|
458 |
|
459 | Model.prototype.fromForm = function(form) {
|
460 | var result;
|
461 | result = {};
|
462 |
|
463 | |
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 | return this.load(result);
|
476 | };
|
477 |
|
478 | Model.prototype.exists = function() {
|
479 | return this.constructor.exists(this.id);
|
480 | };
|
481 |
|
482 | Model.prototype.update = function(options) {
|
483 | var clone, records;
|
484 | this.trigger('beforeUpdate', options);
|
485 | records = this.constructor.irecords;
|
486 | records[this.id].load(this.attributes());
|
487 | this.constructor.sort();
|
488 | clone = records[this.id].clone();
|
489 | clone.trigger('update', options);
|
490 | clone.trigger('change', 'update', options);
|
491 | return clone;
|
492 | };
|
493 |
|
494 | Model.prototype.create = function(options) {
|
495 | var clone, record;
|
496 | this.trigger('beforeCreate', options);
|
497 | this.id || (this.id = this.cid);
|
498 | record = this.dup(false);
|
499 | this.constructor.addRecord(record);
|
500 | this.constructor.sort();
|
501 | clone = record.clone();
|
502 | clone.trigger('create', options);
|
503 | clone.trigger('change', 'create', options);
|
504 | return clone;
|
505 | };
|
506 |
|
507 | Model.prototype.bind = function(events, callback) {
|
508 | var binder, singleEvent, _fn, _i, _len, _ref;
|
509 | this.constructor.bind(events, binder = (function(_this) {
|
510 | return function(record) {
|
511 | if (record && _this.eql(record)) {
|
512 | return callback.apply(_this, arguments);
|
513 | }
|
514 | };
|
515 | })(this));
|
516 | _ref = events.split(' ');
|
517 | _fn = (function(_this) {
|
518 | return function(singleEvent) {
|
519 | var unbinder;
|
520 | return _this.constructor.bind("unbind", unbinder = function(record, event, cb) {
|
521 | if (record && _this.eql(record)) {
|
522 | if (event && event !== singleEvent) {
|
523 | return;
|
524 | }
|
525 | if (cb && cb !== callback) {
|
526 | return;
|
527 | }
|
528 | _this.constructor.unbind(singleEvent, binder);
|
529 | return _this.constructor.unbind("unbind", unbinder);
|
530 | }
|
531 | });
|
532 | };
|
533 | })(this);
|
534 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
535 | singleEvent = _ref[_i];
|
536 | _fn(singleEvent);
|
537 | }
|
538 | return this;
|
539 | };
|
540 |
|
541 | Model.prototype.one = function(events, callback) {
|
542 | var handler;
|
543 | return this.bind(events, handler = (function(_this) {
|
544 | return function() {
|
545 | _this.unbind(events, handler);
|
546 | return callback.apply(_this, arguments);
|
547 | };
|
548 | })(this));
|
549 | };
|
550 |
|
551 | Model.prototype.trigger = function() {
|
552 | var args, _ref;
|
553 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
554 | args.splice(1, 0, this);
|
555 | return (_ref = this.constructor).trigger.apply(_ref, args);
|
556 | };
|
557 |
|
558 | Model.prototype.listenTo = function() {
|
559 | return Events.listenTo.apply(this, arguments);
|
560 | };
|
561 |
|
562 | Model.prototype.listenToOnce = function() {
|
563 | return Events.listenToOnce.apply(this, arguments);
|
564 | };
|
565 |
|
566 | Model.prototype.stopListening = function() {
|
567 | return Events.stopListening.apply(this, arguments);
|
568 | };
|
569 |
|
570 | Model.prototype.unbind = function(events, callback) {
|
571 | var event, _i, _len, _ref, _results;
|
572 | if (arguments.length === 0) {
|
573 | return this.trigger('unbind');
|
574 | } else if (events) {
|
575 | _ref = events.split(' ');
|
576 | _results = [];
|
577 | for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
578 | event = _ref[_i];
|
579 | _results.push(this.trigger('unbind', event, callback));
|
580 | }
|
581 | return _results;
|
582 | }
|
583 | };
|
584 |
|
585 | return Model;
|
586 |
|
587 | })(Module);
|
588 |
|
589 | Model.prototype.on = Model.prototype.bind;
|
590 |
|
591 | Model.prototype.off = Model.prototype.unbind;
|
592 |
|
593 | createObject = Object.create || function(o) {
|
594 | var Func;
|
595 | Func = function() {};
|
596 | Func.prototype = o;
|
597 | return new Func();
|
598 | };
|
599 |
|
600 | isArray = function(value) {
|
601 | return Object.prototype.toString.call(value) === '[object Array]';
|
602 | };
|
603 |
|
604 | isBlank = function(value) {
|
605 | var key;
|
606 | if (!value) {
|
607 | return true;
|
608 | }
|
609 | for (key in value) {
|
610 | return false;
|
611 | }
|
612 | return true;
|
613 | };
|
614 |
|
615 | makeArray = function(args) {
|
616 | return Array.prototype.slice.call(args, 0);
|
617 | };
|
618 |
|
619 | Model.isBlank = isBlank;
|
620 |
|
621 | Model.sub = function(instances, statics) {
|
622 | var Result;
|
623 | Result = (function(_super) {
|
624 | __extends(Result, _super);
|
625 |
|
626 | function Result() {
|
627 | return Result.__super__.constructor.apply(this, arguments);
|
628 | }
|
629 |
|
630 | return Result;
|
631 |
|
632 | })(this);
|
633 | if (instances) {
|
634 | Result.include(instances);
|
635 | }
|
636 | if (statics) {
|
637 | Result.extend(statics);
|
638 | }
|
639 | if (typeof Result.unbind === "function") {
|
640 | Result.unbind();
|
641 | }
|
642 | return Result;
|
643 | };
|
644 |
|
645 | Model.setup = function(name, attributes) {
|
646 | var Instance;
|
647 | if (attributes == null) {
|
648 | attributes = [];
|
649 | }
|
650 | Instance = (function(_super) {
|
651 | __extends(Instance, _super);
|
652 |
|
653 | function Instance() {
|
654 | return Instance.__super__.constructor.apply(this, arguments);
|
655 | }
|
656 |
|
657 | return Instance;
|
658 |
|
659 | })(this);
|
660 | Instance.configure.apply(Instance, [name].concat(__slice.call(attributes)));
|
661 | return Instance;
|
662 | };
|
663 |
|
664 | Model.host = "";
|
665 |
|
666 | if (typeof module !== "undefined" && module !== null) {
|
667 | module.exports = Model;
|
668 | }
|
669 |
|
670 | }).call(this);
|