yodel_admin 0.0.5 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -53,7 +53,7 @@
53
53
  $('#save_failure').fadeIn().delay(2000).fadeOut();
54
54
  <% end %>
55
55
 
56
- <% record.field_sections.each do |section| %>
56
+ <% record.field_sections.values.each do |section| %>
57
57
  <% if section.display? %>
58
58
  <section>
59
59
  <% if section.name.present? %>
@@ -62,6 +62,7 @@
62
62
  <div <% if section.name.present? %> style="display: none" <% end %>>
63
63
  <%= form.form_for_section(section) %>
64
64
  </div>
65
+ <div style="clear: both"></div>
65
66
  </section>
66
67
  <% end %>
67
68
  <% end %>
@@ -45,6 +45,17 @@
45
45
  </header>
46
46
  <%= content %>
47
47
 
48
+
49
+ <div id="alert-background" style="display: none"></div>
50
+ <div id="alert" style="display: none">
51
+ <h1>Error</h1>
52
+ <p>Error text here</p>
53
+ <menu>
54
+ <a href="#" class="dismiss">Cancel</a>
55
+ <a href="#" class="confirm">OK</a>
56
+ </menu>
57
+ </div>
58
+
48
59
  <script src="/admin/js/jquery.tablesorter.min.js"></script>
49
60
  <script src="/admin/chosen/chosen.jquery.min.js"></script>
50
61
  <script src="/admin/js/jquery-ui-1.8.16.custom.min.js"></script>
@@ -12,7 +12,7 @@
12
12
  <h1>New</h1>
13
13
  <ul>
14
14
  <% site.models.each do |model| %>
15
- <% next if model.name.end_with?('_eigenmodel') || model.name.end_with?('Eigenmodel') %>
15
+ <% next if model.name.end_with?('_eigenmodel') || model.name.end_with?('Eigenmodel') || model.hide_in_admin %>
16
16
  <a href="#" class="model" data-type="<%= model.name %>" data-model-id="<%= model.id %>">
17
17
  <li>
18
18
  <img src="/admin/images/load_spinner.gif" class="spinner">
@@ -1,6 +1,7 @@
1
1
  <h1><span class="type"><%= @record.model_name.underscore.humanize.titleize %></span> <span id="record_name"><%= @record.name %></span></h1>
2
2
  <% form_for @record, page.path, remote: true, params: {id: 'record_form'} do |form| %>
3
3
  <% form.success do %>
4
+ // TODO: the form may need to be re-generated: the state of the form may not be the state that was submitted
4
5
  $('#save_success').fadeIn().delay(2000).fadeOut();
5
6
 
6
7
  // remove the model and parent id's regardless of whether this was a new or existing record
@@ -11,47 +12,82 @@
11
12
  $('#record_id').remove();
12
13
  $('#record_form').append('<input type="hidden" id="record_id" name="id" value="' + record.id + '">');
13
14
 
15
+ // update embedded record ids
16
+ var values = jQuery.parseJSON(record.values);
17
+ updateEmbeddedRecordIds(values);
18
+
19
+ // and image and attachment names
20
+ updateImageAndAttachmentNames(values);
21
+
14
22
  // further saves are updates
15
23
  $('#record_form input[name=_method]').val('put');
16
24
 
17
25
  // update the UI to reflect any changes in the record
18
26
  $('#record_name').html(record.name)
19
27
  updateRecord(record);
20
- var values = jQuery.parseJSON(record.values);
21
- if(values) {
22
- $('#record_form .field-type-attachment, #record_form .field-type-image').each(function(index, element) {
23
- element = jQuery(element);
24
- var field_name = element.attr('data-field');
25
-
26
- var file_name = 'none';
27
-
28
- if(values[field_name] && values[field_name].name) {
29
- file_name = values[field_name].name;
30
- element.find('img').attr('src', '/attachments/' + field_name + '/' + values._id + '/admin_thumb.jpg');
31
- element.find('img').show();
32
- element.find('.clear').show();
33
- element.find('input[type=file]').val('');
34
- } else {
35
- element.find('.clear').hide();
36
- }
37
- element.find('p span').html(file_name);
38
- });
39
- }
40
28
  <% end %>
41
29
 
42
30
  <% form.failure do %>
43
31
  $('#save_failure').fadeIn().delay(2000).fadeOut();
44
32
  <% end %>
45
33
 
46
- <% @record.field_sections.each do |section| %>
34
+ <% @record.field_sections.values.each do |section| %>
47
35
  <% if section.display? %>
36
+
48
37
  <section>
49
38
  <% if section.name.present? %>
50
39
  <h1><%= section.name %> <a href="#" class="section_toggle">show</a></h1>
51
40
  <% end %>
41
+
52
42
  <div <% if section.name.present? %> style="display: none" <% end %>>
53
- <%= form.form_for_section(section) %>
43
+ <% section.displayed_fields.each do |field| %>
44
+
45
+ <% if field.type == 'many_embedded' %>
46
+ <div
47
+ class='contains-field-type-<%= field.type %>'
48
+ data-field-human-name="<%= field.name.underscore.singularize.humanize.downcase %>"
49
+ data-field-name="<%= field.name %>">
50
+ <% if form.prefix %>
51
+ <input type="hidden" name="<%= form.prefix %>[][<%= field.name %>]" value="">
52
+ <% else %>
53
+ <input type="hidden" name="<%= field.name %>[]" value="">
54
+ <% end %>
55
+
56
+ <%= form.label(field.name) %>
57
+
58
+ <div>
59
+ <p class="no-embedded" <% unless @record.get(field.name).empty? %>style="display: none"<% end %>>
60
+ No <%= field.name.underscore.pluralize.humanize.downcase %>
61
+ </p>
62
+ <span class="field-type-many_embedded">
63
+ <% form.field(field.name, blank_record: true) do |embedded_form| %>
64
+ <% if embedded_form.record.new? %>
65
+ <span class="embedded-record blank-record">
66
+ <input type="hidden" name="<%= field.name %>[][_id]" value="">
67
+ <%= embedded_form.form_for_section(embedded_form.record.field_sections[nil]) %>
68
+ <% else %>
69
+ <span class="embedded-record" id="<%= embedded_form.record.id.to_s %>">
70
+ <input type="hidden" name="<%= field.name %>[][_id]" value="<%= embedded_form.record.id.to_s %>">
71
+ <%= embedded_form.form_for_section(embedded_form.record.field_sections[nil]) %>
72
+ <% end %>
73
+ <p class="delete-embedded"><a href="#">Delete</a></p>
74
+ <div style="clear: both"></div>
75
+ </span>
76
+ <% end %>
77
+ </span>
78
+
79
+ <%= form.status(field.name) %>
80
+ <p class="add-embedded"><a href="#">Add <%= field.name.underscore.singularize.humanize.downcase %></a></p>
81
+ </div>
82
+ </div>
83
+
84
+ <% else %>
85
+ <%= form.field_row(field.name, field) %>
86
+ <div style="clear: both"></div>
87
+ <% end %>
88
+ <% end %>
54
89
  </div>
90
+ <div style="clear: both"></div>
55
91
  </section>
56
92
  <% end %>
57
93
  <% end %>
@@ -170,6 +170,136 @@ header {
170
170
 
171
171
 
172
172
 
173
+ /* ---------------------------------------------------- */
174
+ /* alert dialog */
175
+ /* ---------------------------------------------------- */
176
+ #alert-background {
177
+ background-color: black;
178
+ position: fixed;
179
+ top: 0px;
180
+ left: 0px;
181
+ width: 100%;
182
+ height: 100%;
183
+
184
+ /* rgba is only supported by IE 9 */
185
+ opacity: 0.2;
186
+ -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=20)";
187
+ filter: alpha(opacity=20);
188
+ }
189
+
190
+ #alert {
191
+ background-color: white;
192
+ border: 2px solid #191919;
193
+ -webkit-border-radius: 6px;
194
+ -moz-border-radius: 6px;
195
+ border-radius: 6px;
196
+ -webkit-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
197
+ -moz-box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
198
+ box-shadow: 0 3px 7px rgba(0, 0, 0, 0.3);
199
+
200
+ position: fixed;
201
+ width: 450px;
202
+ top: 50%;
203
+ left: 50%;
204
+ margin-left: -175px;
205
+ margin-top: -100px;
206
+ }
207
+
208
+ #alert h1 {
209
+ background-color: #2a2a2a;
210
+ padding: 12px 20px 14px 20px;
211
+ font-size: 18px;
212
+ margin-bottom: 10px;
213
+ color: #eee;
214
+
215
+ -webkit-border-top-left-radius: 3px;
216
+ -moz-border-radius-topleft: 3px;
217
+ border-top-left-radius: 3px;
218
+
219
+ -webkit-border-top-right-radius: 3px;
220
+ -moz-border-radius-topright: 3px;
221
+ border-top-right-radius: 3px;
222
+ }
223
+
224
+ #alert p {
225
+ padding: 20px 20px;
226
+ font-size: 15px;
227
+ line-height: 20px;
228
+ }
229
+
230
+ #alert menu {
231
+ background-color: #fdfdfd;
232
+ border-top: 1px solid #eee;
233
+ padding: 12px 17px;
234
+ text-align: right;
235
+ margin-top: 10px;
236
+
237
+ -webkit-border-bottom-left-radius: 3px;
238
+ -moz-border-radius-bottomleft: 3px;
239
+ border-bottom-left-radius: 3px;
240
+
241
+ -webkit-border-bottom-right-radius: 3px;
242
+ -moz-border-radius-bottomright: 3px;
243
+ border-bottom-right-radius: 3px;
244
+ }
245
+
246
+ #alert menu a {
247
+ cursor: pointer;
248
+ display: inline-block;
249
+ background-color: #e6e6e6;
250
+ background-repeat: no-repeat;
251
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));
252
+ background-image: -webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
253
+ background-image: -moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);
254
+ background-image: -ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
255
+ background-image: -o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
256
+ background-image: linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);
257
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
258
+ padding: 5px 14px 6px;
259
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75);
260
+ color: #333;
261
+ font-size: 13px;
262
+ line-height: normal;
263
+ border: 1px solid #ccc;
264
+ border-bottom-color: #bbb;
265
+ -webkit-border-radius: 4px;
266
+ -moz-border-radius: 4px;
267
+ border-radius: 4px;
268
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
269
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
270
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05);
271
+ -webkit-transition: 0.1s linear all;
272
+ -moz-transition: 0.1s linear all;
273
+ -ms-transition: 0.1s linear all;
274
+ -o-transition: 0.1s linear all;
275
+ transition: 0.1s linear all;
276
+ }
277
+
278
+ #alert menu a:active {
279
+ background-position: 0 -15px;
280
+ color: #333;
281
+ text-decoration: none;
282
+ }
283
+
284
+ #alert menu a.confirm {
285
+ margin-left: 10px;
286
+ color: #ffffff !important;
287
+ background-color: #0064cd;
288
+ background-repeat: repeat-x;
289
+ background-image: -khtml-gradient(linear, left top, left bottom, from(#049cdb), to(#0064cd));
290
+ background-image: -moz-linear-gradient(top, #049cdb, #0064cd);
291
+ background-image: -ms-linear-gradient(top, #049cdb, #0064cd);
292
+ background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #049cdb), color-stop(100%, #0064cd));
293
+ background-image: -webkit-linear-gradient(top, #049cdb, #0064cd);
294
+ background-image: -o-linear-gradient(top, #049cdb, #0064cd);
295
+ background-image: linear-gradient(top, #049cdb, #0064cd);
296
+ filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#049cdb', endColorstr='#0064cd', GradientType=0);
297
+ text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
298
+ border-color: #0064cd #0064cd #003f81;
299
+ border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
300
+ }
301
+
302
+
173
303
  /* ---------------------------------------------------- */
174
304
  /* main content containers */
175
305
  /* ---------------------------------------------------- */
@@ -300,12 +430,17 @@ article {
300
430
  float: left;
301
431
  }
302
432
 
303
- #record form > section > div > div > div {
433
+
434
+ #record form > section > div > div > div, /* top level, main record field */
435
+ .field-type-many_embedded > span > div > div, /* field of a many embedded record */
436
+ .field-type-one_embedded > span > div > div /* field of a single embedded record */
437
+ {
304
438
  padding-left: 110px;
305
439
  padding-right: 30px;
306
440
  vertical-align: top;
307
441
  }
308
442
 
443
+
309
444
  /* FIXME: html isn't added as a class to the div */
310
445
  #record form div.html {
311
446
  padding-right: 20px;
@@ -369,8 +504,13 @@ article {
369
504
  display: none;
370
505
  }
371
506
 
372
- .contains-field-type-image {
507
+ .contains-field-type-image, .contains-field-type-image + div {
373
508
  clear: both;
509
+ margin-top: 15px;
510
+ }
511
+
512
+ .contains-field-type-image {
513
+ min-height: 82px;
374
514
  }
375
515
 
376
516
  #record .image_preview {
@@ -427,6 +567,33 @@ article {
427
567
  width: auto;
428
568
  }
429
569
 
570
+ /* embedded fields */
571
+ .no-embedded, .add-embedded, .delete-embedded {
572
+ color: #777;
573
+ font-size: 13px;
574
+ }
575
+
576
+ .add-embedded, .delete-embedded {
577
+ text-align: right;
578
+ padding-right: 20px;
579
+ margin-top: 20px;
580
+ }
581
+
582
+ .add-embedded a, .delete-embedded a {
583
+ color: #777;
584
+ }
585
+
586
+ .delete-embedded {
587
+ clear: both;
588
+ }
589
+
590
+ .field-type-many_embedded > span {
591
+ display: block;
592
+ margin-bottom: 10px;
593
+ border-bottom: 1px solid #ccc;
594
+ padding-bottom: 10px;
595
+ }
596
+
430
597
  /* validations */
431
598
  .yodel-field-status {
432
599
  display: block;
@@ -11,11 +11,23 @@ function initialiseWidgets(newRecord) {
11
11
  hideModelPanel();
12
12
  initialiseHTMLFields();
13
13
  initialiseMultipleSelectFields();
14
+ initialiseEmbeddedFields();
14
15
  addClearLinks();
15
16
  if(newRecord)
16
17
  setDateTimeFieldsToNow();
17
18
  }
18
19
 
20
+ var blankRecords = {};
21
+ function initialiseEmbeddedFields() {
22
+ blankRecords = {};
23
+ $('.field-type-many_embedded .blank-record').each(function(index, record) {
24
+ var blankRecord = $(record);
25
+ blankRecord.hide();
26
+ blankRecord.removeClass('blank-record');
27
+ blankRecords[$(record).closest('.contains-field-type-many_embedded').attr('data-field-name')] = blankRecord.detach();
28
+ });
29
+ }
30
+
19
31
  function setDateTimeFieldsToNow() {
20
32
  // TODO: should check that each field is blank first before setting; a default value may have been set
21
33
  var now = new Date();
@@ -161,7 +173,7 @@ function constructRecordList(tree) {
161
173
  var navigationPanels = [];
162
174
 
163
175
  function dragError(parent, oldIndex, row) {
164
- alert('Sorry, an error occurred updating the position of this record. Please reload the page and try again.');
176
+ showAlert('Update error', 'Sorry, an error occurred updating the position of this record. Please reload the page and try again.');
165
177
 
166
178
  // move the row back to its old position; record indexes are 1 based
167
179
  if(oldIndex == 1) {
@@ -221,7 +233,7 @@ function pushNavigationPanel(rootName, tree, isPageRoot) {
221
233
  if(record && record.parent_id)
222
234
  parent = findRecord(tree, record.parent_id);
223
235
  if(!parent) {
224
- alert("Sorry, an error occurred updating the position of this record (the parent record could not be found). Please refresh the page and try again.");
236
+ showAlert('Update error', "Sorry, an error occurred updating the position of this record (the parent record could not be found). Please refresh the page and try again.");
225
237
  return;
226
238
  }
227
239
 
@@ -350,6 +362,57 @@ function hideChildren(event) {
350
362
  }
351
363
 
352
364
 
365
+ function updateEmbeddedRecordIds(record, embeddedIdElements) {
366
+ if(!embeddedIdElements)
367
+ embeddedIdElements = $.makeArray($('.embedded-record input[name*="_id"]'));
368
+
369
+ $.each(record, function(field, value) {
370
+ if(!value)
371
+ return;
372
+ if(value['_id']) {
373
+ $(embeddedIdElements.shift()).val(value['_id']);
374
+ } else if($.isArray(value)) {
375
+ updateEmbeddedRecordIds(value, embeddedIdElements);
376
+ }
377
+ });
378
+ }
379
+
380
+ function updateImageAndAttachmentNames(record, fieldElements, idStack) {
381
+ if(!fieldElements)
382
+ fieldElements = $.makeArray($('.field-type-attachment, .field-type-image'));
383
+ if(!idStack)
384
+ idStack = [record['_id']];
385
+
386
+ $.each(record, function(field, value) {
387
+ if(!value)
388
+ return;
389
+
390
+ if(!(value['name'] === undefined) && !(value['mime'] === undefined)) {
391
+ var field = $(fieldElements.shift());
392
+ if(value['name'] != null) {
393
+ var field_name = field.attr('data-field').replace(/\[\]/g, '').replace(/\[/g, '_').replace(/\]/g, '');
394
+ field.find('p span').html(value['name']);
395
+ field.find('img').attr('src', '/attachments/' + field_name + '/' + idStack.join('/') + '/admin_thumb.jpg');
396
+ field.find('img').show();
397
+ field.find('.clear').show();
398
+ field.find('input[type=file]').val('');
399
+ } else {
400
+ field.find('p span').html('none');
401
+ field.find('.clear').hide();
402
+ }
403
+
404
+ } else if(value['_id']) {
405
+ idStack.push(value['_id']);
406
+ updateImageAndAttachmentNames(value, fieldElements, idStack);
407
+ idStack.pop();
408
+
409
+ } else if($.isArray(value)) {
410
+ updateImageAndAttachmentNames(value, fieldElements, idStack);
411
+ }
412
+ });
413
+ }
414
+
415
+
353
416
  // update an existing record or add a record to the tree
354
417
  function updateRecord(record) {
355
418
  // either find the parent record by searching from the root of the
@@ -367,7 +430,7 @@ function updateRecord(record) {
367
430
  parent = findRecord(tree, record.parent_id);
368
431
 
369
432
  if(!treeRecord && !parent) {
370
- alert("Sorry, an error occurred while creating this record (no parent or record could be found). Please refresh the page and try again.");
433
+ showAlert('Create error', "Sorry, an error occurred while creating this record (no parent or record could be found). Please refresh the page and try again.");
371
434
  return;
372
435
  }
373
436
 
@@ -481,7 +544,9 @@ function deleteButtonPressed(event) {
481
544
  var recordTypeName = types[recordRow.attr('data-type')].humanName;
482
545
  var recordID = recordRow.attr('data-record-id');
483
546
 
484
- if(confirm('Are you sure you want to delete this ' + recordTypeName + '?')) {
547
+ showAlert('Confirm delete', 'Are you sure you want to delete this ' + recordTypeName + '?', function(ok) {
548
+ if(!ok)
549
+ return;
485
550
  showSpinner(recordRow);
486
551
  $.ajax(jsonURL, {
487
552
  data: {id: recordID, _method: 'delete'},
@@ -529,10 +594,10 @@ function deleteButtonPressed(event) {
529
594
  }, error: function(jqXHR, textStatus, errorThrown) {
530
595
  // FIXME: better error message
531
596
  hideSpinner(recordRow);
532
- alert('Sorry, an error occurred deleting this record. Please reload the page and try again.');
597
+ showAlert('Delete error', 'Sorry, an error occurred deleting this record. Please reload the page and try again.');
533
598
  }
534
599
  });
535
- }
600
+ });
536
601
  }
537
602
 
538
603
 
@@ -609,52 +674,58 @@ function toggleSectionVisibility(event) {
609
674
  }
610
675
 
611
676
 
612
- // delete an embedded doc
613
- function deleteEmbeddedDoc(event) {
677
+ // delete an embedded record
678
+ function deleteEmbeddedRecord(event) {
614
679
  event.preventDefault();
615
680
  var target = $(event.target);
616
- var documents = target.parents('div.embedded_documents');
617
- var type = documents.attr('data-type');
681
+ var fieldContainer = target.closest('div.contains-field-type-many_embedded');
682
+ var records = fieldContainer.find('.field-type-many_embedded');
683
+ var type = fieldContainer.attr('data-field-human-name');
618
684
 
619
- if(confirm('Are you sure you want to delete this ' + type + '?')) {
620
- target.parents('div.embedded_document').animate({
685
+ showAlert('Confirm delete', 'Are you sure you want to delete this ' + type + '?', function(ok) {
686
+ if(!ok)
687
+ return;
688
+
689
+ target.closest('.embedded-record').animate({
621
690
  height: 'hide',
622
691
  opacity: 'hide'
623
692
  }, {
624
693
  complete: function() {
625
694
  // show the 'No TYPE' text if we are removing the last embedded doc in a collection
626
- if(documents.find('div.embedded_document').size() == 1)
627
- documents.find('.no_embedded_documents').animate({height: 'show', opacity: 'show'});
695
+ if(records.find('> span').size() == 1)
696
+ fieldContainer.find('.no-embedded').animate({height: 'show', opacity: 'show'});
628
697
  $(this).remove();
629
698
  }
630
699
  });
631
- }
700
+ });
701
+
632
702
  }
633
703
 
634
- // add a new embedded doc
635
- function addEmbeddedDoc(event) {
704
+ // add a new embedded record
705
+ function addEmbeddedRecord(event) {
636
706
  event.preventDefault();
637
707
  var target = $(event.target);
638
- var documents = target.parents('div.embedded_documents');
708
+ var fieldContainer = target.closest('div');
709
+ var records = fieldContainer.find('.field-type-many_embedded');
710
+ var blankRecord = blankRecords[fieldContainer.closest('.contains-field-type-many_embedded').attr('data-field-name')];
639
711
 
640
- // construct a new document form an insert in to the collection
641
- var doc = $('<div class="embedded_document" style="display: none"><a href="#" class="delete_embedded_document"></a><table><tr><td id="label_col"></td><td id="input_col"></td></tr><tr><td><label>Photo</label></td><td><div class="attachment photo"><div class="photo_preview"><img src="sample_photo.jpg"></div><p class="current_value"><span class="title">File:</span>train.jpeg <a href="#" class="clear">Clear</a></p><p><span class="title">Select:</span><input type="file"></p><input type="hidden" name="delete_X" class="delete" value="false"></div></td></tr><tr><td><label>Name</label></td><td><input type="text"></td></tr></table></div>');
642
- $(event.target).before(doc);
712
+ var newRecord = blankRecord.clone();
713
+ $(records).append(newRecord);
643
714
 
644
- // hide the 'No TYPE' text if we are adding a new embedded doc in to an empty collection
645
- // animate the insertion of the new doc after hiding the 'No TYPE' text or immediately
646
- if(documents.find('div.embedded_document').size() == 1) {
647
- documents.find('.no_embedded_documents').animate({
715
+ //hide the 'No TYPE' text if we are adding a new embedded record in to an empty collection
716
+ // animate the insertion of the new record after hiding the 'No TYPE' text or immediately
717
+ if(records.find('> span').size() == 1) {
718
+ fieldContainer.find('.no-embedded').animate({
648
719
  height: 'hide',
649
720
  opacity: 'hide'
650
721
  }, {
651
722
  duration: 150,
652
723
  complete: function() {
653
- doc.animate({height: 'show', opacity: 'show'});
724
+ newRecord.animate({height: 'show', opacity: 'show'});
654
725
  }
655
726
  });
656
727
  } else {
657
- doc.animate({height: 'show', opacity: 'show'});
728
+ newRecord.animate({height: 'show', opacity: 'show'});
658
729
  }
659
730
  }
660
731
 
@@ -668,8 +739,8 @@ $('input[type=file]').live('change', hideClear);
668
739
 
669
740
  $('a.prev_nav_panel').live('click', showPreviousNavigationPanel);
670
741
  $('a.section_toggle').live('click', toggleSectionVisibility);
671
- $('a.delete_embedded_document').live('click', deleteEmbeddedDoc);
672
- $('a.add_embedded_document').live('click', addEmbeddedDoc);
742
+ $('.delete-embedded a').live('click', deleteEmbeddedRecord);
743
+ $('p.add-embedded a').live('click', addEmbeddedRecord);
673
744
 
674
745
  $('h1.new').live('click', showModelPanel);
675
746
  $('div.add_child').live('click', showModelPanel);
@@ -715,9 +786,16 @@ function highlightSelectedRow(row) {
715
786
  // load an existing record's form
716
787
  function loadRecord(id) {
717
788
  $('#record').load(htmlURL + '?action=show&id=' + id, function(text, status, req) {
718
- highlightSelectedRow(id);
719
- hideModelPanel();
720
- initialiseWidgets();
789
+ if(status == 'error') {
790
+ showAlert('Load error', 'Sorry, an error occurred loading this record. Please refresh the page and try again.');
791
+ } else {
792
+ highlightSelectedRow(id);
793
+ hideModelPanel();
794
+ initialiseWidgets();
795
+ setTimeout(function() {
796
+ $('#record').scrollTop(0);
797
+ }, 100);
798
+ }
721
799
  });
722
800
  }
723
801
 
@@ -752,11 +830,27 @@ function loadNewRecord(modelID, parentID, modelWasSelected) {
752
830
 
753
831
  // load the blank default record
754
832
  $('#record').load(htmlURL + '?action=new&model=' + modelID + '&parent=' + parentID, function(text, status, req) {
755
- initialiseWidgets(true);
756
- if(parent.children.length == 0)
757
- highlightSelectedRow(parentID);
758
- else
759
- highlightSelectedRow($('.record[data-record-id=' + parentID + '] > .child_elements > li > h1.new'));
833
+ if(status == 'error') {
834
+ // hide spinners from the navigation menu
835
+ if(parent.children.length == 0)
836
+ hideSpinner(parentID);
837
+ else
838
+ hideSpinner($('.record[data-record-id=' + parentID + '] > .child_elements > li > h1.new'));
839
+
840
+ // hide spinners from the new model panel
841
+ $('a.model .spinner').hide();
842
+ $('a.model .icon').show();
843
+
844
+ showAlert('Unable to load new record', 'Sorry, an error occurred loading a new record. Please refresh the page and try again.')
845
+
846
+ } else {
847
+ initialiseWidgets(true);
848
+ $('#record').scrollTop(0);
849
+ if(parent.children.length == 0)
850
+ highlightSelectedRow(parentID);
851
+ else
852
+ highlightSelectedRow($('.record[data-record-id=' + parentID + '] > .child_elements > li > h1.new'));
853
+ }
760
854
  });
761
855
  }
762
856
 
@@ -814,17 +908,17 @@ function push(creating) {
814
908
  jQuery.ajax(SYNC_URL, {type: 'POST', success: function(data) {
815
909
  if(!data.success) {
816
910
  if(data.reason)
817
- alert(errorText + ": " + data.reason);
911
+ showAlert('Push failed', errorText + ": " + data.reason);
818
912
  else if(data.conflicts)
819
- alert("The following files are in conflict and need to be resolved before pushing: " + data.conflicts.join(','));
913
+ showAlert('Push failed', "The following files are in conflict and need to be resolved before pushing: " + data.conflicts.join(','));
820
914
  else
821
- alert(errorText + ".");
915
+ showAlert('Push failed', errorText + ".");
822
916
  } else if(creating) {
823
917
  window.open('http://' + data.remoteDomain + '/', 'livesite');
824
918
  window.location.reload()
825
919
  }
826
920
  }, error: function(jqXHR, textStatus, errorThrown) {
827
- alert(errorText + ".");
921
+ showAlert('Push failed', errorText + ".");
828
922
  }, complete: function(jqXHR, textStatus) {
829
923
  hideSyncStatus();
830
924
  }});
@@ -849,11 +943,11 @@ $('.sync.create').live('click', function(event) {
849
943
  if(data.success) {
850
944
  push(true);
851
945
  } else {
852
- alert("Sorry, an error occurred while creating this site on the remote server: " + data.reason);
946
+ showAlert('Create failed', "Sorry, an error occurred while creating this site on the remote server: " + data.reason);
853
947
  hideSyncStatus();
854
948
  }
855
949
  }, error: function(jqXHR, textStatus, errorThrown) {
856
- alert("Sorry, an error occurred while creating this site on the remote server.");
950
+ showAlert('Create failed', "Sorry, an error occurred while creating this site on the remote server.");
857
951
  hideSyncStatus();
858
952
  }});
859
953
  });
@@ -869,16 +963,16 @@ $('.sync.pull').live('click', function(event) {
869
963
  jQuery.ajax(SYNC_URL, {type: 'GET', success: function(data) {
870
964
  if(!data.success) {
871
965
  if(data.reason)
872
- alert(errorText + ": " + data.reason);
966
+ showAlert('Pull failed', errorText + ": " + data.reason);
873
967
  else if(data.requires_push)
874
- alert(errorText + ": No remote server is associated with this site");
968
+ showAlert('Pull failed', errorText + ": No remote server is associated with this site");
875
969
  else if(data.conflicts)
876
- alert("The following files are in conflict and need to be resolved before pulling: " + data.conflicts.join(','));
970
+ showAlert('Pull failed', "The following files are in conflict and need to be resolved before pulling: " + data.conflicts.join(','));
877
971
  else
878
- alert(errorText + ".");
972
+ showAlert('Pull failed', errorText + ".");
879
973
  }
880
974
  }, error: function(jqXHR, textStatus, errorThrown) {
881
- alert(errorText + ".");
975
+ showAlert('Pull failed', errorText + ".");
882
976
  }, complete: function(jqXHR, textStatus) {
883
977
  hideSyncStatus();
884
978
  }});
@@ -960,7 +1054,7 @@ $('#list_items tbody tr').live('click', function() {
960
1054
  $('#record').load(htmlURL + '?id=' + recordID, function(text, status, req) {
961
1055
  $('#activity_spinner').fadeOut();
962
1056
  if(status == 'error') {
963
- alert("Sorry, an error occurred loading this record. Please refresh the page and try again.");
1057
+ showAlert('Load error', "Sorry, an error occurred loading this record. Please refresh the page and try again.");
964
1058
  } else {
965
1059
  highlightSelectedListRow(row);
966
1060
  initialiseWidgets();
@@ -1000,7 +1094,10 @@ $('.list #record .delete').live('click', function(event) {
1000
1094
  var recordID = $(event.target).attr('data-record-id');
1001
1095
  var recordTypeName = $(event.target).attr('data-record-type');
1002
1096
 
1003
- if(confirm('Are you sure you want to delete this ' + recordTypeName + '?')) {
1097
+ showAlert('Confirm delete', 'Are you sure you want to delete this ' + recordTypeName + '?', function(ok) {
1098
+ if(!ok)
1099
+ return;
1100
+
1004
1101
  $('#delete_spinner').fadeIn();
1005
1102
  $.ajax(jsonURL, {
1006
1103
  data: {id: recordID, _method: 'delete'},
@@ -1014,13 +1111,13 @@ $('.list #record .delete').live('click', function(event) {
1014
1111
 
1015
1112
  }, error: function(jqXHR, textStatus, errorThrown) {
1016
1113
  // FIXME: better error message
1017
- alert('Sorry, an error occurred deleting this record. Please reload the page and try again.');
1114
+ showAlert('Delete error', 'Sorry, an error occurred deleting this record. Please reload the page and try again.');
1018
1115
 
1019
1116
  }, complete: function() {
1020
1117
  $('#delete_spinner').fadeOut();
1021
1118
  }
1022
1119
  });
1023
- }
1120
+ });
1024
1121
  });
1025
1122
 
1026
1123
  $('#new_record').live('click', function(event) {
@@ -1031,7 +1128,7 @@ $('#new_record').live('click', function(event) {
1031
1128
  $('#record').load(htmlURL + '?new=true', function(text, status, req) {
1032
1129
  $('#activity_spinner').fadeOut();
1033
1130
  if(status == 'error') {
1034
- alert("Sorry, an error occurred loading a new record form. Please refresh the page and try again.");
1131
+ showAlert('Load error', "Sorry, an error occurred loading a new record. Please refresh the page and try again.");
1035
1132
  } else {
1036
1133
  highlightSelectedListRow();
1037
1134
  initialiseWidgets();
@@ -1040,3 +1137,84 @@ $('#new_record').live('click', function(event) {
1040
1137
  });
1041
1138
  })
1042
1139
 
1140
+
1141
+
1142
+
1143
+ /* alert modal dialog */
1144
+ var alertShowing = false;
1145
+ var confirmCallback = null;
1146
+
1147
+ // callback is null for simple 'OK' alerts; pass a
1148
+ // callback for a confirm ('Cancel', 'OK') alert
1149
+ function showAlert(title, text, callback) {
1150
+ // TODO: queue alerts in order
1151
+ if(alertShowing) {
1152
+ setTimeout(function() {
1153
+ showAlert(title, text, callback);
1154
+ }, 500);
1155
+ return;
1156
+ }
1157
+
1158
+ alertShowing = true;
1159
+ confirmCallback = callback;
1160
+ $('#alert h1').html(title);
1161
+ $('#alert p').html(text);
1162
+
1163
+ if(callback) {
1164
+ $('#alert menu a.confirm').show();
1165
+ $('#alert menu a.confirm').html('OK');
1166
+ $('#alert menu a.dismiss').html('Cancel');
1167
+ } else {
1168
+ $('#alert menu a.confirm').hide();
1169
+ $('#alert menu a.dismiss').html('OK');
1170
+ }
1171
+
1172
+ $('#alert-background').fadeIn('fast');
1173
+ $('#alert').fadeIn('fast');
1174
+ }
1175
+
1176
+ function hideAlert() {
1177
+ $('#alert-background').fadeOut('fast');
1178
+ $('#alert').fadeOut('fast');
1179
+ alertShowing = false;
1180
+ }
1181
+
1182
+ function cancelAlert() {
1183
+ if(confirmCallback)
1184
+ confirmCallback(false);
1185
+ confirmCallback = null;
1186
+ hideAlert();
1187
+ }
1188
+
1189
+ function confirmAlert() {
1190
+ if(confirmCallback)
1191
+ confirmCallback(true);
1192
+ confirmCallback = null;
1193
+ hideAlert();
1194
+ }
1195
+
1196
+ $('#alert menu a.dismiss').click(function(event) {
1197
+ event.preventDefault();
1198
+ cancelAlert();
1199
+ });
1200
+
1201
+ $('#alert menu a.confirm').click(function(event) {
1202
+ event.preventDefault();
1203
+ confirmAlert();
1204
+ });
1205
+
1206
+ $(document).keyup(function(event) {
1207
+ if(!alertShowing)
1208
+ return;
1209
+
1210
+ // enter/return
1211
+ if(event.which == 13)
1212
+ if(confirmCallback)
1213
+ confirmAlert();
1214
+ else
1215
+ cancelAlert();
1216
+
1217
+ // escape
1218
+ else if(event.which == 27)
1219
+ cancelAlert();
1220
+ });
@@ -1,3 +1,3 @@
1
1
  module YodelAdmin
2
- VERSION = '0.0.5'
2
+ VERSION = '0.0.7'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yodel_admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.5
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-18 00:00:00.000000000Z
12
+ date: 2012-01-07 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: Yodel CMS Admin Extension
15
15
  email: