modeljs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,543 @@
1
+
2
+ String.prototype.capitalize = function() {
3
+ return this.charAt(0).toUpperCase() + this.slice(1);
4
+ };
5
+
6
+ var all_models = [];
7
+
8
+ var Model = function(params) {
9
+ this.init(params);
10
+ all_models.push(this);
11
+ };
12
+
13
+ Model.attribute_options = {};
14
+
15
+ Model.get_attribute_options = function(model_name, attribute_name)
16
+ {
17
+ if (Model.attribute_options[model_name] == null) return false;
18
+ if (Model.attribute_options[model_name][attribute_name] == null) return false;
19
+ return Model.attribute_options[model_name][attribute_name];
20
+ };
21
+
22
+ Model.set_attribute_options = function(model_name, attribute_name, options)
23
+ {
24
+ if (Model.attribute_options[model_name] == null)
25
+ Model.attribute_options[model_name] = {};
26
+ Model.attribute_options[model_name][attribute_name] = options;
27
+ };
28
+
29
+ Model.upload_finished = function(resp)
30
+ {
31
+ $(all_models).each(function (i, m) {
32
+ if (m.name == resp.name && m.id == resp.id) {
33
+ $(m.attributes).each(function(j, attrib) {
34
+ if (attrib.name == resp.attribute_name) {
35
+ attrib.upload_finished(resp);
36
+ return false;
37
+ }
38
+ });
39
+ return false;
40
+ }
41
+ });
42
+ };
43
+
44
+ Model.dashed_to_camel_case = function(str) {
45
+ var arr = [];
46
+ $.each(str.toLowerCase().split('-'), function(i, word) {
47
+ arr[arr.length] = word.capitalize();
48
+ });
49
+ return arr.join('');
50
+ };
51
+
52
+ Model.parse_url = function(str, id)
53
+ {
54
+ if (id)
55
+ str = str.replace("{id}", id);
56
+ arr = str.split(' ')
57
+ if (arr.length == 1)
58
+ return { verb: 'get', url: arr[0] };
59
+ return { verb: arr[0], url: arr[1] };
60
+ };
61
+
62
+ Model.prototype = {
63
+
64
+ id: '',
65
+ name: '',
66
+ attributes: [],
67
+ attributes_original: false,
68
+ ca: false, // current attribute being edited
69
+ container: false,
70
+ form: 'Model.Form', // Name of the class that generates add/edit forms for the model
71
+
72
+ // Urls of CRUD events
73
+ create_url: false,
74
+ update_url: false,
75
+ delete_url: false,
76
+ listing_url: false,
77
+
78
+ // After ajax events
79
+ post_add: function() {},
80
+ post_update: function() {},
81
+ post_delete: function() {},
82
+
83
+ // Listings
84
+ listing_edit: false, // Should we allow edits? true, false, or 'inline'
85
+ listing_delete: false, // Should we allow deletes? true, false, or 'inline'
86
+ listing_empty_text: false,
87
+ is_listing: false,
88
+ cl: false, // current listing
89
+
90
+ init: function(params)
91
+ {
92
+ var this2 = this;
93
+
94
+ for (var thing in params)
95
+ this[thing] = params[thing];
96
+
97
+ // Set some defaults
98
+ this.name = this.name.toLowerCase();
99
+ if (!this.create_url ) this.create_url = 'post /' + this.name + 's';
100
+ if (!this.update_url ) this.update_url = 'put /' + this.name + 's/{id}';
101
+ if (!this.delete_url ) this.delete_url = 'delete /' + this.name + 's/{id}';
102
+ if (!this.container ) this.container = this.name.toLowerCase() + '_' + this.id + '_container';
103
+ if (!this.listing_empty_text) this.listing_empty_text = "There are no " + this.name + "s yet.";
104
+
105
+ // Create the model form generator
106
+ if (typeof(this.form) == 'string')
107
+ eval("this.form = new " + this.form + "(this" + (params.form_params ? ", params.form_params": "") + ");");
108
+
109
+ // Attach the model to the dom
110
+ var this2 = this;
111
+ $('input.' + this.name + '_add').click(function() { this2.ajax_add(); });
112
+ $('input.' + this.name + '_' + this.id + '_delete').click(function() { this2.ajax_delete(); });
113
+
114
+ // Create any attributes
115
+ this.attributes_original = this.attributes;
116
+ this.attributes = [];
117
+ $(this.attributes_original).each(function(i, attrib) {
118
+ attrib.base = this2.name + '_' + this2.id + '_' + attrib.name;
119
+ eval("var a = new Model.Attribute." + Model.dashed_to_camel_case(attrib.type) + "(attrib);");
120
+ a.model = this2;
121
+ this2.attributes[this2.attributes.length] = a;
122
+ });
123
+
124
+ if (!this.is_listing && $('#' + this.name + '_listing_container').length && this.listing_url) this.listing();
125
+ if ($('#' + this.name + '_new_container').length) this.add_form();
126
+ else if ($('#' + this.name + '_' + this.id + '_container').length) this.edit_form();
127
+ },
128
+
129
+ listing: function()
130
+ {
131
+ var this2 = this;
132
+ this.verify_attribute_options(function() {
133
+ this2.listing_helper();
134
+ });
135
+ },
136
+
137
+ listing_helper: function()
138
+ {
139
+ var this2 = this;
140
+ this.form.refresh_listing_models(function() {
141
+ this2.listing_helper2();
142
+ });
143
+ },
144
+
145
+ listing_helper2: function()
146
+ {
147
+ var this2 = this;
148
+ if (this2.form.listing_models.length == 0)
149
+ {
150
+ $('#' + this2.name + '_listing_container')
151
+ .empty().append($('<p/>').html(this.listing_empty_text));
152
+ return;
153
+ }
154
+
155
+ var table = $('<table/>').addClass('data');
156
+ var tbody = $('<tbody/>');
157
+ var tr = $('<tr/>');
158
+ $(this2.attributes).each(function(i, a) {
159
+ if (a.type == 'hidden') return;
160
+ tr.append($('<th/>').html(a.nice_name));
161
+ });
162
+ tbody.append(tr);
163
+
164
+ $(this2.form.listing_models).each(function(i, m) {
165
+ var tr = m.form.listing_view();
166
+ tr.attr('id', m.name + '_' + m.id + '_listing_container')
167
+ .addClass('model_listing');
168
+ tbody.append(tr);
169
+ });
170
+ table.append(tbody);
171
+ $('#' + this2.name + '_listing_container').empty().append(table);
172
+
173
+ // Show each attribute
174
+ $(this2.form.listing_models).each(function(i, m) {
175
+ $(m.attributes).each(function(j, a) {
176
+ if (a.type == 'hidden') return;
177
+ m.show_attribute(a);
178
+ $('#' + a.container).children().unbind('click');
179
+ $('#' + a.container).click(function() { m.edit_listing(); });
180
+ });
181
+ });
182
+ },
183
+
184
+ add_form: function()
185
+ {
186
+ // Make sure all the attribute options are populated first
187
+ var this2 = this;
188
+ this.verify_attribute_options(function() {
189
+
190
+ // Then add the form to the DOM
191
+ var div = this2.form.add();
192
+ if (div)
193
+ {
194
+ div.attr('id', this2.name + '_new_form');
195
+ div.submit(function() { return false; });
196
+ $('#' + this2.container).append(div);
197
+ }
198
+
199
+ // Then make each attribute editable
200
+ $(this2.attributes).each(function(i, a) {
201
+ if (a.type != 'hidden')
202
+ this2.edit_attribute_helper(a);
203
+ });
204
+
205
+ // Finally run any post add functionality
206
+ this2.form.post_add_display();
207
+ });
208
+ },
209
+
210
+ edit_form: function()
211
+ {
212
+ // Add the form to the DOM
213
+ var div = this.form.edit();
214
+ if (div)
215
+ {
216
+ div.attr('id', this.container);
217
+ $('#' + this.container).replaceWith(div);
218
+ }
219
+
220
+ // Show each attribute
221
+ var this2 = this;
222
+ $(this.attributes).each(function(i, a) { this2.show_attribute(a); });
223
+
224
+ // Set the escape key to cancel the edit
225
+ $(document).keyup(function(e) {
226
+ if (e.keyCode == 27 && this2.ca)
227
+ this2.show_attribute(this2.ca);
228
+ });
229
+
230
+ // Finally run any post edit functionality
231
+ this.form.post_edit_display();
232
+ },
233
+
234
+ edit_listing: function()
235
+ {
236
+ var this2 = this;
237
+ var tr = this.form.listing_form();
238
+ tr.attr('id', this.name + '_' + this.id + '_listing_container')
239
+ .addClass('edit_listing_form')
240
+ $('#' + this.name + '_' + this.id + '_listing_container').replaceWith(tr);
241
+
242
+ // Add our controls
243
+ var count = this.unhidden_attribute_count();
244
+ controls = $('<tr/>')
245
+ .attr('id', this.name + '_' + this.id + '_listing_controls')
246
+ .addClass('edit_listing_controls')
247
+ .append($('<td/>')
248
+ .attr('colspan', count)
249
+ .append($('<div/>').attr('id', this.form.message))
250
+ .append($('<p/>')
251
+ .append($('<input/>').attr('type', 'button').val('Cancel').click(function() { this2.cancel_edit_listing(); }))
252
+ .append(' ')
253
+ .append($('<input/>').attr('type', 'button').val('Update').click(function() { this2.update_listing(); }))
254
+ .append(' ')
255
+ .append($('<input/>').attr('type', 'button').val('Delete').click(function() {
256
+ this2.post_delete = function() { this2.listing(); };
257
+ this2.ajax_delete();
258
+ }))
259
+ )
260
+ );
261
+ $('#' + this.name + '_' + this.id + '_listing_container').after(controls);
262
+
263
+ // Then make each attribute editable
264
+ $(this.attributes).each(function(i, a) {
265
+ if (a.type != 'hidden')
266
+ this2.edit_attribute_helper(a);
267
+ });
268
+
269
+ // Finally run any post functionality
270
+ this.form.post_listing_form_display();
271
+ },
272
+
273
+ cancel_edit_listing: function()
274
+ {
275
+ var this2 = this;
276
+ var tr = this.form.listing_view();
277
+ tr.attr('id', this.name + '_' + this.id + '_listing_container')
278
+ .addClass('model_listing');
279
+ $('#' + this.name + '_' + this.id + '_listing_container').replaceWith(tr);
280
+ $('#' + this.name + '_' + this.id + '_listing_controls').remove();
281
+
282
+ // Show each attribute
283
+ $(this.attributes).each(function(i, a) {
284
+ if (a.type == 'hidden') return;
285
+ this2.show_attribute(a);
286
+ $('#' + a.container).children().unbind('click');
287
+ $('#' + a.container).click(function() { this2.edit_listing(); });
288
+ });
289
+
290
+ // Finally run any post functionality
291
+ this.form.post_listing_view_display();
292
+ },
293
+
294
+ update_listing: function()
295
+ {
296
+ this.form.loading('Updating...');
297
+ this2 = this;
298
+ obj = Model.parse_url(this.update_url, this.id)
299
+ $.ajax({
300
+ url: obj.url,
301
+ type: obj.verb,
302
+ data: this2.form.add_values(),
303
+ success: function(resp) {
304
+ if (resp.error)
305
+ this2.form.ajax_success(resp);
306
+ else
307
+ {
308
+ $(this2.attributes).each(function(i, a) {
309
+ a.value = a.form_value();
310
+ if (resp.attributes && resp.attributes[a.name])
311
+ for (var thing in resp.attributes[a.name])
312
+ a[thing] = resp.attributes[a.name][thing];
313
+ });
314
+ this2.cancel_edit_listing();
315
+ }
316
+ //this2.form.post_update_listing();
317
+ },
318
+ error: function() {
319
+ this2.form.ajax_error('Error')
320
+ }
321
+ });
322
+ },
323
+
324
+ /****************************************************************************/
325
+
326
+ ajax_add: function()
327
+ {
328
+ this.form.loading(this.form.adding_message);
329
+ this2 = this;
330
+ obj = Model.parse_url(this.create_url, this.id)
331
+ $.ajax({
332
+ url: obj.url,
333
+ type: obj.verb,
334
+ data: this2.form.add_values(),
335
+ success: function(resp) {
336
+ this2.form.ajax_success(resp);
337
+ this2.post_add();
338
+ },
339
+ error: function() {
340
+ this2.form.ajax_error('Error')
341
+ }
342
+ });
343
+ },
344
+
345
+ ajax_update: function(attrib)
346
+ {
347
+ if (attrib.show_controls)
348
+ $('#' + attrib.controls).hide();
349
+
350
+ attrib.loading();
351
+ this2 = this;
352
+ data = attrib.form_values();
353
+ obj = Model.parse_url(attrib.update_url ? attrib.update_url : this.update_url, this.id);
354
+ $.ajax({
355
+ url: obj.url,
356
+ type: obj.verb,
357
+ data: data,
358
+ success: function(resp) {
359
+ if (resp.error)
360
+ {
361
+ if (attrib.show_controls)
362
+ $('#' + attrib.controls).show();
363
+ attrib.error(resp.error);
364
+ }
365
+ if (resp.success)
366
+ {
367
+ attrib.value = attrib.form_value();
368
+ if (resp.attributes && resp.attributes[attrib.name])
369
+ {
370
+ var a = resp.attributes[attrib.name];
371
+ for (var thing in a)
372
+ attrib[thing] = a[thing];
373
+ }
374
+ this2.show_attribute(attrib);
375
+ this2.post_update();
376
+ }
377
+ },
378
+ error: function() {
379
+ if (attrib.show_controls)
380
+ $('#' + attrib.controls).show();
381
+ attrib.error("Error during update.");
382
+ }
383
+ });
384
+ },
385
+
386
+ ajax_delete: function(confirm)
387
+ {
388
+ if (!confirm)
389
+ {
390
+ var this2 = this;
391
+ this.form.confirm({
392
+ message: this.form.delete_message,
393
+ yes: function() { this2.ajax_delete(true); }
394
+ });
395
+ return;
396
+ }
397
+
398
+ this.form.loading(this.form.deleting_message);
399
+ this2 = this;
400
+ obj = Model.parse_url(this.delete_url, this.id)
401
+ $.ajax({
402
+ url: obj.url,
403
+ type: obj.verb,
404
+ success: function(resp) {
405
+ this2.form.ajax_success(resp);
406
+ this2.post_delete();
407
+ },
408
+ error: function() {
409
+ this2.form.ajax_error('Error');
410
+ }
411
+ });
412
+ },
413
+
414
+ /****************************************************************************/
415
+
416
+ get_attribute: function(attribute_name)
417
+ {
418
+ var count = this.attributes.length;
419
+ for (var i=0; i<count; i++)
420
+ if (this.attributes[i].name == attribute_name)
421
+ return this.attributes[i];
422
+ return false;
423
+ },
424
+
425
+ // Populate attribute options
426
+ verify_attribute_options: function(done, i)
427
+ {
428
+ if (i >= this.attributes.length)
429
+ {
430
+ done();
431
+ return;
432
+ }
433
+ if (!i) i = 0;
434
+ var a = this.attributes[i];
435
+
436
+ if (!a.needs_options() || Model.get_attribute_options(this.name, a.name))
437
+ {
438
+ this.verify_attribute_options(done, i+1);
439
+ return;
440
+ }
441
+
442
+ var this2 = this;
443
+ $.ajax({
444
+ url: a.options_url,
445
+ success: function(resp) {
446
+ Model.set_attribute_options(this2.name, a.name, resp);
447
+ this2.verify_attribute_options(done, i+1);
448
+ }
449
+ });
450
+ },
451
+
452
+ show_attribute: function(attrib)
453
+ {
454
+ if (typeof(attrib) == 'string')
455
+ attrib = this.get_attribute(attrib);
456
+
457
+ var this2 = this;
458
+ var div = attrib.view();
459
+ if (!this.is_listing && div.html().length == 0)
460
+ div.html('[Empty]');
461
+ div.addClass('model_attribute model_attribute_' + attrib.type);
462
+ div.click(function() { this2.edit_attribute(attrib.name); });
463
+
464
+ $('#' + attrib.container).empty().append(div);
465
+ this.ca = false;
466
+ attrib.post_view_display();
467
+ },
468
+
469
+ edit_attribute: function(attrib)
470
+ {
471
+ if (typeof(attrib) == 'string')
472
+ attrib = this.get_attribute(attrib);
473
+
474
+ if (this.id != 'new' && this.ca)
475
+ this.show_attribute(this.ca);
476
+ this.ca = attrib;
477
+
478
+ if (attrib.custom_form)
479
+ {
480
+ var form = attrib.form();
481
+ $('#' + attrib.container).empty().append(form);
482
+ attrib.post_form_display();
483
+ return;
484
+ }
485
+
486
+ if (!attrib.needs_options() || Model.get_attribute_options(this.name, attrib.name))
487
+ {
488
+ this.edit_attribute_helper(attrib);
489
+ return;
490
+ }
491
+
492
+ $('#' + attrib.container).empty().append($('<p/>').addClass('loading_small').html(attrib.loading_message));
493
+
494
+ this2 = this;
495
+ $.ajax({
496
+ url: attrib.options_url,
497
+ success: function(resp) {
498
+ Model.set_attribute_options(this2.name, attrib.name, resp);
499
+ this2.edit_attribute_helper(attrib);
500
+ }
501
+ });
502
+ },
503
+
504
+ edit_attribute_helper: function(attrib)
505
+ {
506
+ var this2 = this;
507
+ var form = attrib.form();
508
+ form.attr('id', attrib.base + '_form')
509
+ .addClass('model_attribute_form model_attribute_form_' + attrib.type)
510
+ .submit(function () { return false; });
511
+
512
+ if (this.id != 'new')
513
+ {
514
+ var controls = $('<div/>')
515
+ .attr('id', attrib.controls)
516
+ .append($('<input/>').attr('type', 'submit').val('Update').addClass('update_btn').click(function() { this2.ajax_update(attrib); }))
517
+ .append($('<input/>').attr('type', 'button').val('Cancel').addClass('cancel_btn').click(function() { this2.show_attribute(attrib); }));
518
+ form.append(controls);
519
+ }
520
+ form.append($('<span/>').attr('id', attrib.message));
521
+
522
+ if (this.id == 'new')
523
+ $('#' + attrib.container).empty().append(form.children());
524
+ else
525
+ {
526
+ $('#' + attrib.container).empty().append(form);
527
+ if (!attrib.show_controls)
528
+ $('#' + attrib.controls).hide();
529
+ }
530
+ attrib.post_form_display();
531
+ },
532
+
533
+ unhidden_attribute_count: function()
534
+ {
535
+ var count = 0;
536
+ $(this.attributes).each(function(i, a) {
537
+ if (a.type == 'hidden') return;
538
+ count++;
539
+ });
540
+ return count;
541
+ }
542
+
543
+ };