modeljs 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ };