populate-me 0.12.0

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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/Gemfile +3 -0
  4. data/LICENSE +20 -0
  5. data/README.md +655 -0
  6. data/Rakefile +14 -0
  7. data/example/config.ru +100 -0
  8. data/lib/populate_me.rb +2 -0
  9. data/lib/populate_me/admin.rb +157 -0
  10. data/lib/populate_me/admin/__assets__/css/asmselect.css +63 -0
  11. data/lib/populate_me/admin/__assets__/css/jquery-ui.min.css +6 -0
  12. data/lib/populate_me/admin/__assets__/css/main.css +244 -0
  13. data/lib/populate_me/admin/__assets__/img/help/children.png +0 -0
  14. data/lib/populate_me/admin/__assets__/img/help/create.png +0 -0
  15. data/lib/populate_me/admin/__assets__/img/help/delete.png +0 -0
  16. data/lib/populate_me/admin/__assets__/img/help/edit.png +0 -0
  17. data/lib/populate_me/admin/__assets__/img/help/form.png +0 -0
  18. data/lib/populate_me/admin/__assets__/img/help/list.png +0 -0
  19. data/lib/populate_me/admin/__assets__/img/help/login.png +0 -0
  20. data/lib/populate_me/admin/__assets__/img/help/logout.png +0 -0
  21. data/lib/populate_me/admin/__assets__/img/help/menu.png +0 -0
  22. data/lib/populate_me/admin/__assets__/img/help/overview.png +0 -0
  23. data/lib/populate_me/admin/__assets__/img/help/save.png +0 -0
  24. data/lib/populate_me/admin/__assets__/img/help/sort.png +0 -0
  25. data/lib/populate_me/admin/__assets__/img/help/sublist.png +0 -0
  26. data/lib/populate_me/admin/__assets__/js/asmselect.js +412 -0
  27. data/lib/populate_me/admin/__assets__/js/columnav.js +87 -0
  28. data/lib/populate_me/admin/__assets__/js/jquery-ui.min.js +7 -0
  29. data/lib/populate_me/admin/__assets__/js/main.js +388 -0
  30. data/lib/populate_me/admin/__assets__/js/mustache.js +578 -0
  31. data/lib/populate_me/admin/__assets__/js/sortable.js +2 -0
  32. data/lib/populate_me/admin/views/help.erb +94 -0
  33. data/lib/populate_me/admin/views/page.erb +189 -0
  34. data/lib/populate_me/api.rb +124 -0
  35. data/lib/populate_me/attachment.rb +186 -0
  36. data/lib/populate_me/document.rb +192 -0
  37. data/lib/populate_me/document_mixins/admin_adapter.rb +149 -0
  38. data/lib/populate_me/document_mixins/callbacks.rb +125 -0
  39. data/lib/populate_me/document_mixins/outcasting.rb +83 -0
  40. data/lib/populate_me/document_mixins/persistence.rb +95 -0
  41. data/lib/populate_me/document_mixins/schema.rb +198 -0
  42. data/lib/populate_me/document_mixins/typecasting.rb +70 -0
  43. data/lib/populate_me/document_mixins/validation.rb +44 -0
  44. data/lib/populate_me/file_system_attachment.rb +40 -0
  45. data/lib/populate_me/grid_fs_attachment.rb +103 -0
  46. data/lib/populate_me/mongo.rb +160 -0
  47. data/lib/populate_me/s3_attachment.rb +120 -0
  48. data/lib/populate_me/variation.rb +38 -0
  49. data/lib/populate_me/version.rb +4 -0
  50. data/populate-me.gemspec +34 -0
  51. data/test/helper.rb +37 -0
  52. data/test/test_admin.rb +183 -0
  53. data/test/test_api.rb +246 -0
  54. data/test/test_attachment.rb +167 -0
  55. data/test/test_document.rb +128 -0
  56. data/test/test_document_admin_adapter.rb +221 -0
  57. data/test/test_document_callbacks.rb +151 -0
  58. data/test/test_document_outcasting.rb +247 -0
  59. data/test/test_document_persistence.rb +83 -0
  60. data/test/test_document_schema.rb +280 -0
  61. data/test/test_document_typecasting.rb +128 -0
  62. data/test/test_grid_fs_attachment.rb +239 -0
  63. data/test/test_mongo.rb +324 -0
  64. data/test/test_s3_attachment.rb +281 -0
  65. data/test/test_variation.rb +91 -0
  66. data/test/test_version.rb +11 -0
  67. metadata +294 -0
@@ -0,0 +1,412 @@
1
+ /*
2
+ * Alternate Select Multiple (asmSelect) 1.0.4a beta - jQuery Plugin
3
+ * http://www.ryancramer.com/projects/asmselect/
4
+ *
5
+ * Copyright (c) 2009 by Ryan Cramer - http://www.ryancramer.com
6
+ *
7
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
8
+ * and GPL (GPL-LICENSE.txt) licenses.
9
+ *
10
+ */
11
+
12
+ // The references to $.browser where commented out because it
13
+ // breaks with newer version of jQuery.
14
+
15
+ (function($) {
16
+
17
+ $.fn.asmSelect = function(customOptions) {
18
+
19
+ var options = {
20
+
21
+ listType: 'ol', // Ordered list 'ol', or unordered list 'ul'
22
+ sortable: false, // Should the list be sortable?
23
+ highlight: false, // Use the highlight feature?
24
+ animate: false, // Animate the the adding/removing of items in the list?
25
+ addItemTarget: 'bottom', // Where to place new selected items in list: top or bottom
26
+ hideWhenAdded: false, // Hide the option when added to the list? works only in FF
27
+ debugMode: false, // Debug mode keeps original select visible
28
+
29
+ removeLabel: 'remove', // Text used in the "remove" link
30
+ highlightAddedLabel: 'Added: ', // Text that precedes highlight of added item
31
+ highlightRemovedLabel: 'Removed: ', // Text that precedes highlight of removed item
32
+
33
+ containerClass: 'asmContainer', // Class for container that wraps this widget
34
+ selectClass: 'asmSelect', // Class for the newly created <select>
35
+ optionDisabledClass: 'asmOptionDisabled', // Class for items that are already selected / disabled
36
+ listClass: 'asmList', // Class for the list ($ol)
37
+ listSortableClass: 'asmListSortable', // Another class given to the list when it is sortable
38
+ listItemClass: 'asmListItem', // Class for the <li> list items
39
+ listItemLabelClass: 'asmListItemLabel', // Class for the label text that appears in list items
40
+ removeClass: 'asmListItemRemove', // Class given to the "remove" link
41
+ highlightClass: 'asmHighlight' // Class given to the highlight <span>
42
+
43
+ };
44
+
45
+ $.extend(options, customOptions);
46
+
47
+ return this.each(function(index) {
48
+
49
+ var $original = $(this); // the original select multiple
50
+ var $container; // a container that is wrapped around our widget
51
+ var $select; // the new select we have created
52
+ var $ol; // the list that we are manipulating
53
+ var buildingSelect = false; // is the new select being constructed right now?
54
+ var ieClick = false; // in IE, has a click event occurred? ignore if not
55
+ var ignoreOriginalChangeEvent = false; // originalChangeEvent bypassed when this is true
56
+
57
+ function init() {
58
+
59
+ // initialize the alternate select multiple
60
+
61
+ // this loop ensures uniqueness, in case of existing asmSelects placed by ajax (1.0.3)
62
+ while($("#" + options.containerClass + index).size() > 0) index++;
63
+
64
+ $select = $("<select></select>")
65
+ .addClass(options.selectClass)
66
+ .attr('name', options.selectClass + index)
67
+ .attr('id', options.selectClass + index);
68
+
69
+ $selectRemoved = $("<select></select>");
70
+
71
+ $ol = $("<" + options.listType + "></" + options.listType + ">")
72
+ .addClass(options.listClass)
73
+ .attr('id', options.listClass + index);
74
+
75
+ $container = $("<div></div>")
76
+ .addClass(options.containerClass)
77
+ .attr('id', options.containerClass + index);
78
+
79
+ buildSelect();
80
+
81
+ $select.change(selectChangeEvent)
82
+ .click(selectClickEvent);
83
+
84
+ $original.change(originalChangeEvent)
85
+ .wrap($container).before($select).before($ol);
86
+
87
+ if(options.sortable) makeSortable();
88
+
89
+ // if($.browser.msie && $.browser.version < 8) $ol.css('display', 'inline-block'); // Thanks Matthew Hutton
90
+ }
91
+
92
+ function makeSortable() {
93
+
94
+ // make any items in the selected list sortable
95
+ // requires jQuery UI sortables, draggables, droppables
96
+
97
+ $ol.sortable({
98
+ items: 'li.' + options.listItemClass,
99
+ handle: '.' + options.listItemLabelClass,
100
+ axis: 'y',
101
+ update: function(e, data) {
102
+
103
+ var updatedOptionId;
104
+
105
+ $(this).children("li").each(function(n) {
106
+
107
+ $option = $('#' + $(this).attr('rel'));
108
+
109
+ if($(this).is(".ui-sortable-helper")) {
110
+ updatedOptionId = $option.attr('id');
111
+ return;
112
+ }
113
+
114
+ $original.append($option);
115
+ });
116
+
117
+ if(updatedOptionId) triggerOriginalChange(updatedOptionId, 'sort');
118
+ }
119
+
120
+ }).addClass(options.listSortableClass);
121
+ }
122
+
123
+ function selectChangeEvent(e) {
124
+
125
+ // an item has been selected on the regular select we created
126
+ // check to make sure it's not an IE screwup, and add it to the list
127
+
128
+ // if($.browser.msie && $.browser.version < 7 && !ieClick) return;
129
+ var id = $(this).children("option:selected").slice(0,1).attr('rel');
130
+ addListItem(id);
131
+ ieClick = false;
132
+ triggerOriginalChange(id, 'add'); // for use by user-defined callbacks
133
+ }
134
+
135
+ function selectClickEvent() {
136
+
137
+ // IE6 lets you scroll around in a select without it being pulled down
138
+ // making sure a click preceded the change() event reduces the chance
139
+ // if unintended items being added. there may be a better solution?
140
+
141
+ ieClick = true;
142
+ }
143
+
144
+ function originalChangeEvent(e) {
145
+
146
+ // select or option change event manually triggered
147
+ // on the original <select multiple>, so rebuild ours
148
+
149
+ if(ignoreOriginalChangeEvent) {
150
+ ignoreOriginalChangeEvent = false;
151
+ return;
152
+ }
153
+
154
+ $select.empty();
155
+ $ol.empty();
156
+ buildSelect();
157
+
158
+ // opera has an issue where it needs a force redraw, otherwise
159
+ // the items won't appear until something else forces a redraw
160
+ // if($.browser.opera) $ol.hide().fadeIn("fast");
161
+ }
162
+
163
+ function buildSelect() {
164
+
165
+ // build or rebuild the new select that the user
166
+ // will select items from
167
+
168
+ buildingSelect = true;
169
+
170
+ // add a first option to be the home option / default selectLabel
171
+ $select.prepend("<option>" + $original.attr('title') + "</option>");
172
+
173
+ $original.children("option").each(function(n) {
174
+
175
+ var $t = $(this);
176
+ var id;
177
+
178
+ if(!$t.attr('id')) $t.attr('id', 'asm' + index + 'option' + n);
179
+ id = $t.attr('id');
180
+
181
+ if($t.is(":selected")) {
182
+ addListItem(id);
183
+ addSelectOption(id, true);
184
+ } else {
185
+ addSelectOption(id);
186
+ }
187
+ });
188
+
189
+ if(!options.debugMode) $original.hide(); // IE6 requires this on every buildSelect()
190
+ selectFirstItem();
191
+ buildingSelect = false;
192
+ }
193
+
194
+ function addSelectOption(optionId, disabled) {
195
+
196
+ // add an <option> to the <select>
197
+ // used only by buildSelect()
198
+
199
+ if(disabled == undefined) var disabled = false;
200
+
201
+ var $O = $('#' + optionId);
202
+ var $option = $("<option>" + $O.text() + "</option>")
203
+ .val($O.val())
204
+ .attr('rel', optionId);
205
+
206
+ if(disabled) disableSelectOption($option);
207
+
208
+ $select.append($option);
209
+ }
210
+
211
+ function selectFirstItem() {
212
+
213
+ // select the firm item from the regular select that we created
214
+
215
+ $select.children(":eq(0)").attr("selected", true);
216
+ }
217
+
218
+ function disableSelectOption($option) {
219
+
220
+ // make an option disabled, indicating that it's already been selected
221
+ // because safari is the only browser that makes disabled items look 'disabled'
222
+ // we apply a class that reproduces the disabled look in other browsers
223
+
224
+ $option.addClass(options.optionDisabledClass)
225
+ .attr("selected", false)
226
+ .attr("disabled", true);
227
+
228
+ if(options.hideWhenAdded) $option.hide();
229
+ // if($.browser.msie) $select.hide().show(); // this forces IE to update display
230
+ if(true) $select.hide().show(); // this forces IE to update display
231
+ }
232
+
233
+ function enableSelectOption($option) {
234
+
235
+ // given an already disabled select option, enable it
236
+
237
+ $option.removeClass(options.optionDisabledClass)
238
+ .attr("disabled", false);
239
+
240
+ if(options.hideWhenAdded) $option.show();
241
+ // if($.browser.msie) $select.hide().show(); // this forces IE to update display
242
+ if(true) $select.hide().show(); // this forces IE to update display
243
+ }
244
+
245
+ function addListItem(optionId) {
246
+
247
+ // add a new item to the html list
248
+
249
+ var $O = $('#' + optionId);
250
+
251
+ if(!$O) return; // this is the first item, selectLabel
252
+
253
+ var $removeLink = $("<a></a>")
254
+ .attr("href", "#")
255
+ .addClass(options.removeClass)
256
+ .prepend(options.removeLabel)
257
+ .click(function() {
258
+ dropListItem($(this).parent('li').attr('rel'));
259
+ return false;
260
+ });
261
+
262
+ var $itemLabel = $("<span></span>")
263
+ .addClass(options.listItemLabelClass)
264
+ .html($O.html());
265
+
266
+ var $item = $("<li></li>")
267
+ .attr('rel', optionId)
268
+ .addClass(options.listItemClass)
269
+ .append($itemLabel)
270
+ .append($removeLink)
271
+ .hide();
272
+
273
+ if(!buildingSelect) {
274
+ if($O.is(":selected")) return; // already have it
275
+ $O.attr('selected', true);
276
+ }
277
+
278
+ if(options.addItemTarget == 'top' && !buildingSelect) {
279
+ $ol.prepend($item);
280
+ if(options.sortable) $original.prepend($O);
281
+ } else {
282
+ $ol.append($item);
283
+ if(options.sortable) $original.append($O);
284
+ }
285
+
286
+ addListItemShow($item);
287
+
288
+ disableSelectOption($("[rel=" + optionId + "]", $select));
289
+
290
+ if(!buildingSelect) {
291
+ setHighlight($item, options.highlightAddedLabel);
292
+ selectFirstItem();
293
+ if(options.sortable) $ol.sortable("refresh");
294
+ }
295
+
296
+ }
297
+
298
+ function addListItemShow($item) {
299
+
300
+ // reveal the currently hidden item with optional animation
301
+ // used only by addListItem()
302
+
303
+ if(options.animate && !buildingSelect) {
304
+ $item.animate({
305
+ opacity: "show",
306
+ height: "show"
307
+ }, 100, "swing", function() {
308
+ $item.animate({
309
+ height: "+=2px"
310
+ }, 50, "swing", function() {
311
+ $item.animate({
312
+ height: "-=2px"
313
+ }, 25, "swing");
314
+ });
315
+ });
316
+ } else {
317
+ $item.show();
318
+ }
319
+ }
320
+
321
+ function dropListItem(optionId, highlightItem) {
322
+
323
+ // remove an item from the html list
324
+
325
+ if(highlightItem == undefined) var highlightItem = true;
326
+ var $O = $('#' + optionId);
327
+
328
+ $O.attr('selected', false);
329
+ $item = $ol.children("li[rel=" + optionId + "]");
330
+
331
+ dropListItemHide($item);
332
+ enableSelectOption($("[rel=" + optionId + "]", options.removeWhenAdded ? $selectRemoved : $select));
333
+
334
+ if(highlightItem) setHighlight($item, options.highlightRemovedLabel);
335
+
336
+ triggerOriginalChange(optionId, 'drop');
337
+
338
+ }
339
+
340
+ function dropListItemHide($item) {
341
+
342
+ // remove the currently visible item with optional animation
343
+ // used only by dropListItem()
344
+
345
+ if(options.animate && !buildingSelect) {
346
+
347
+ $prevItem = $item.prev("li");
348
+
349
+ $item.animate({
350
+ opacity: "hide",
351
+ height: "hide"
352
+ }, 100, "linear", function() {
353
+ $prevItem.animate({
354
+ height: "-=2px"
355
+ }, 50, "swing", function() {
356
+ $prevItem.animate({
357
+ height: "+=2px"
358
+ }, 100, "swing");
359
+ });
360
+ $item.remove();
361
+ });
362
+
363
+ } else {
364
+ $item.remove();
365
+ }
366
+ }
367
+
368
+ function setHighlight($item, label) {
369
+
370
+ // set the contents of the highlight area that appears
371
+ // directly after the <select> single
372
+ // fade it in quickly, then fade it out
373
+
374
+ if(!options.highlight) return;
375
+
376
+ $select.next("#" + options.highlightClass + index).remove();
377
+
378
+ var $highlight = $("<span></span>")
379
+ .hide()
380
+ .addClass(options.highlightClass)
381
+ .attr('id', options.highlightClass + index)
382
+ .html(label + $item.children("." + options.listItemLabelClass).slice(0,1).text());
383
+
384
+ $select.after($highlight);
385
+
386
+ $highlight.fadeIn("fast", function() {
387
+ setTimeout(function() { $highlight.fadeOut("slow"); }, 50);
388
+ });
389
+ }
390
+
391
+ function triggerOriginalChange(optionId, type) {
392
+
393
+ // trigger a change event on the original select multiple
394
+ // so that other scripts can pick them up
395
+
396
+ ignoreOriginalChangeEvent = true;
397
+ $option = $("#" + optionId);
398
+
399
+ $original.trigger('change', [{
400
+ 'option': $option,
401
+ 'value': $option.val(),
402
+ 'id': optionId,
403
+ 'item': $ol.children("[rel=" + optionId + "]"),
404
+ 'type': type
405
+ }]);
406
+ }
407
+
408
+ init();
409
+ });
410
+ };
411
+
412
+ })(jQuery);
@@ -0,0 +1,87 @@
1
+ (function($){
2
+
3
+ $.fn.columnav = function(options) {
4
+
5
+ var settings = $.extend({
6
+ column_class: 'column',
7
+ link_class: 'column-push',
8
+ selected_link_class: 'selected',
9
+ on_push: function(){},
10
+ on_pop: function(){},
11
+ process_data: function(data){return data;}
12
+ }, options );
13
+
14
+ var new_column = function(el, root) {
15
+ var $el = $(el).css({
16
+ display: 'inline-block',
17
+ verticalAlign: 'top',
18
+ whiteSpace: 'normal',
19
+ listStyle: 'none'
20
+ });
21
+ $('.'+settings.link_class, $el)
22
+ .on('click.columnav', function(e,cb) {
23
+ if (!root.busy) {
24
+ root.busy = true;
25
+ $('.'+settings.link_class, $el).removeClass(settings.selected_link_class);
26
+ var $this = $(this).addClass(settings.selected_link_class);
27
+ var removable = $this.parents('.'+settings.column_class).nextAll();
28
+ if (removable.length === 0) {
29
+ root.trigger('getandpush.columnav',[$this.attr('href'),cb]);
30
+ } else {
31
+ root.trigger('pop.columnav',[removable,function(cb_info) {
32
+ root.trigger('getandpush.columnav',[$this.attr('href'),cb]);
33
+ }]);
34
+ }
35
+ }
36
+ e.preventDefault();
37
+ });
38
+ };
39
+
40
+ return this.each(function(){
41
+ var root = $(this).css({
42
+ overflow: 'scroll',
43
+ whiteSpace: 'nowrap'
44
+ });
45
+ root.busy = false;
46
+ root.on('push.columnav', function(e,data,cb) {
47
+ var $data = $("<li class='"+settings.column_class+"'>"+data+"</li>");
48
+ root.append($data);
49
+ new_column($data, root);
50
+ var cb_object = {event:e,column:$data,container:root,settings:settings};
51
+ root.animate({scrollLeft: root.width()},function(){
52
+ root.busy = false;
53
+ settings.on_push(cb_object);
54
+ if (typeof cb == 'function') cb(cb_object);
55
+ });
56
+ });
57
+ root.on('getandpush.columnav', function(e,url,cb) {
58
+ $.get(url, function(data) {
59
+ root.trigger('push.columnav',[settings.process_data(data),function(cb_object) {
60
+ cb_object.column.data('href',url);
61
+ if (typeof cb == 'function') cb(cb_object);
62
+ }]);
63
+ });
64
+ });
65
+ root.on('pop.columnav', function(e,removable,cb) {
66
+ removable = removable || root.children().last();
67
+ removable.css({visibility:'hidden'})
68
+ .animate({width:0},function(){
69
+ // Trick to make sure it runs only once
70
+ // not for each column removed
71
+ if (removable.filter(':animated').length === 0) {
72
+ removable.remove();
73
+ var cb_object = {event:e,container:root,settings:settings}
74
+ settings.on_pop(cb_object);
75
+ if (typeof cb == 'function') cb(cb_object);
76
+ }
77
+ });
78
+ });
79
+ root.children().each(function() {
80
+ new_column(this, root);
81
+ });
82
+ });
83
+
84
+ };
85
+
86
+ }(jQuery));
87
+