populate-me 0.12.0

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