puffer 0.0.32 → 0.1.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 (117) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +1 -26
  3. data/Gemfile.lock +66 -64
  4. data/README.md +34 -23
  5. data/Rakefile +1 -11
  6. data/VERSION +1 -1
  7. data/app/assets/javascripts/puffer/application.js +6 -1
  8. data/app/assets/javascripts/puffer/associations.js +18 -0
  9. data/app/assets/javascripts/puffer/puffer.js +7 -0
  10. data/app/assets/javascripts/puffer/right-calendar-src.js +19 -3
  11. data/app/assets/javascripts/puffer/right-dnd-src.js +591 -0
  12. data/app/assets/javascripts/puffer/right-in-edit-src.js +373 -0
  13. data/app/assets/javascripts/puffer/right-keys-src.js +87 -0
  14. data/app/assets/javascripts/puffer/{paginator.js → right-paginator-src.js} +0 -0
  15. data/app/assets/javascripts/puffer/right-slider-src.js +29 -32
  16. data/app/assets/javascripts/puffer/right-sortable-src.js +430 -0
  17. data/app/assets/javascripts/puffer/right-src.js +358 -99
  18. data/app/assets/stylesheets/puffer/puffer.css +29 -4
  19. data/app/components/base/form.html.erb +8 -14
  20. data/app/components/base_component.rb +1 -1
  21. data/app/components/boolean/form.html.erb +5 -3
  22. data/app/components/boolean/index.html.erb +6 -2
  23. data/app/components/boolean_component.rb +2 -2
  24. data/app/components/date_time/filter.html.erb +9 -0
  25. data/app/components/date_time/form.html.erb +8 -4
  26. data/app/components/date_time_component.rb +21 -5
  27. data/app/components/file/form.html.erb +8 -4
  28. data/app/components/hidden/form.html.erb +3 -1
  29. data/app/components/nested_attributes_many/form.html.erb +47 -0
  30. data/app/components/nested_attributes_many_component.rb +7 -0
  31. data/app/components/nested_attributes_one/form.html.erb +48 -0
  32. data/app/components/nested_attributes_one_component.rb +7 -0
  33. data/app/components/password/form.html.erb +8 -4
  34. data/app/components/password_component.rb +1 -1
  35. data/app/components/references_many/index.html.erb +1 -1
  36. data/app/components/references_one/choose.html.erb +1 -1
  37. data/app/components/references_one/form.html.erb +10 -9
  38. data/app/components/references_one_component.rb +0 -1
  39. data/app/components/render_component.rb +13 -0
  40. data/app/components/select/filter.html.erb +4 -2
  41. data/app/components/select/form.html.erb +8 -4
  42. data/app/components/text/form.html.erb +8 -4
  43. data/app/controllers/admin/sessions_controller.rb +1 -21
  44. data/app/controllers/puffer/base.rb +10 -3
  45. data/app/controllers/puffer/dashboard_base.rb +7 -1
  46. data/app/controllers/puffer/{sessions_base.rb → sessions/base.rb} +10 -7
  47. data/app/controllers/puffer/sessions/clearance.rb +29 -0
  48. data/app/controllers/puffer/{sessions_devise_base.rb → sessions/devise.rb} +1 -1
  49. data/app/controllers/puffer/sessions/simple.rb +28 -0
  50. data/app/controllers/puffer/tree_base.rb +1 -1
  51. data/app/models/puffer_user.rb +3 -0
  52. data/app/views/layouts/puffer.html.erb +3 -3
  53. data/app/views/puffer/base/_edit.html.erb +15 -0
  54. data/app/views/puffer/base/_index.html.erb +26 -0
  55. data/app/views/puffer/base/_show.html.erb +13 -0
  56. data/app/views/puffer/base/_table.html.erb +1 -1
  57. data/app/views/puffer/base/edit.html.erb +1 -15
  58. data/app/views/puffer/base/edit.js.erb +1 -0
  59. data/app/views/puffer/base/index.html.erb +1 -20
  60. data/app/views/puffer/base/index.js.erb +1 -0
  61. data/app/views/puffer/base/new.html.erb +1 -1
  62. data/app/views/puffer/base/show.html.erb +1 -22
  63. data/app/views/puffer/base/show.js.erb +1 -0
  64. data/app/views/puffer/base/update.js.erb +1 -0
  65. data/app/views/puffer/sessions/base/new.html.erb +11 -0
  66. data/app/views/puffer/tree_base/_record.html.erb +1 -1
  67. data/lib/puffer/component.rb +14 -47
  68. data/lib/puffer/controller/auth.rb +13 -9
  69. data/lib/puffer/controller/config.rb +18 -0
  70. data/lib/puffer/controller/mutate.rb +8 -8
  71. data/lib/puffer/engine.rb +5 -0
  72. data/lib/puffer/field.rb +5 -11
  73. data/lib/puffer/filters.rb +86 -56
  74. data/lib/puffer/helpers/component_helper.rb +24 -0
  75. data/lib/puffer/helpers/puffer_helper.rb +65 -0
  76. data/lib/puffer/helpers/puffer_tree_helper.rb +19 -0
  77. data/lib/puffer/orm_adapter/active_record.rb +40 -11
  78. data/lib/puffer/orm_adapter/base.rb +9 -0
  79. data/lib/puffer/orm_adapter/mongoid.rb +32 -9
  80. data/lib/puffer/resource/node.rb +2 -2
  81. data/lib/puffer/resource/routing.rb +30 -16
  82. data/lib/puffer/resource.rb +20 -20
  83. data/lib/puffer/version.rb +3 -0
  84. data/lib/puffer.rb +26 -5
  85. data/puffer.gemspec +34 -296
  86. data/spec/app/components/base_component_spec.rb +1 -1
  87. data/spec/app/components/boolean_component_spec.rb +2 -0
  88. data/spec/app/components/date_time_component_spec.rb +1 -0
  89. data/spec/app/components/file_component_spec.rb +1 -0
  90. data/spec/app/components/hidden_component_spec.rb +1 -0
  91. data/spec/app/components/password_component_spec.rb +2 -0
  92. data/spec/app/components/select_component_spec.rb +1 -0
  93. data/spec/app/components/string_component_spec.rb +1 -0
  94. data/spec/app/components/text_component_spec.rb +1 -0
  95. data/spec/dummy/app/controllers/admin/news_controller.rb +2 -0
  96. data/spec/dummy/app/controllers/admin/profiles_controller.rb +1 -1
  97. data/spec/dummy/app/controllers/admin/users_controller.rb +2 -0
  98. data/spec/dummy/app/controllers/orms/active_record_orm_primals_controller.rb +8 -0
  99. data/spec/dummy/app/helpers/news_helper.rb +7 -0
  100. data/spec/dummy/app/models/active_record_orm/has_many_reference.rb +5 -0
  101. data/spec/dummy/app/models/active_record_orm/has_one_reference.rb +5 -0
  102. data/spec/dummy/app/models/active_record_orm/primal.rb +4 -0
  103. data/spec/dummy/config/environments/development.rb +1 -1
  104. data/spec/dummy/db/migrate/20111120144025_create_active_record_orm_has_one_references.rb +10 -0
  105. data/spec/dummy/db/migrate/20111122203304_create_active_record_orm_has_many_references.rb +10 -0
  106. data/spec/dummy/db/schema.rb +15 -1
  107. data/spec/helpers/puffer_helper_spec.rb +1 -1
  108. data/spec/lib/fields_spec.rb +0 -9
  109. data/spec/lib/filters_spec.rb +4 -8
  110. data/spec/lib/orm_adapter/base_shared.rb +22 -0
  111. data/spec/spec_helper.rb +1 -1
  112. metadata +89 -60
  113. data/app/components/string/form.html.erb +0 -5
  114. data/app/helpers/puffer_helper.rb +0 -51
  115. data/app/helpers/puffer_tree_helper.rb +0 -15
  116. data/app/views/puffer/sessions_base/new.html.erb +0 -11
  117. data/lib/puffer/extensions/form.rb +0 -16
@@ -0,0 +1,430 @@
1
+ /**
2
+ * RightJS-UI Sortable v2.2.0
3
+ * http://rightjs.org/ui/sortable
4
+ *
5
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
6
+ */
7
+ var Sortable = RightJS.Sortable = (function(document, RightJS) {
8
+ /**
9
+ * This module defines the basic widgets constructor
10
+ * it creates an abstract proxy with the common functionality
11
+ * which then we reuse and override in the actual widgets
12
+ *
13
+ * Copyright (C) 2010-2011 Nikolay Nemshilov
14
+ */
15
+
16
+ /**
17
+ * The widget units constructor
18
+ *
19
+ * @param String tag-name or Object methods
20
+ * @param Object methods
21
+ * @return Widget wrapper
22
+ */
23
+ function Widget(tag_name, methods) {
24
+ if (!methods) {
25
+ methods = tag_name;
26
+ tag_name = 'DIV';
27
+ }
28
+
29
+ /**
30
+ * An Abstract Widget Unit
31
+ *
32
+ * Copyright (C) 2010 Nikolay Nemshilov
33
+ */
34
+ var AbstractWidget = new RightJS.Class(RightJS.Element.Wrappers[tag_name] || RightJS.Element, {
35
+ /**
36
+ * The common constructor
37
+ *
38
+ * @param Object options
39
+ * @param String optional tag name
40
+ * @return void
41
+ */
42
+ initialize: function(key, options) {
43
+ this.key = key;
44
+ var args = [{'class': 'rui-' + key}];
45
+
46
+ // those two have different constructors
47
+ if (!(this instanceof RightJS.Input || this instanceof RightJS.Form)) {
48
+ args.unshift(tag_name);
49
+ }
50
+ this.$super.apply(this, args);
51
+
52
+ if (RightJS.isString(options)) {
53
+ options = RightJS.$(options);
54
+ }
55
+
56
+ // if the options is another element then
57
+ // try to dynamically rewrap it with our widget
58
+ if (options instanceof RightJS.Element) {
59
+ this._ = options._;
60
+ if ('$listeners' in options) {
61
+ options.$listeners = options.$listeners;
62
+ }
63
+ options = {};
64
+ }
65
+ this.setOptions(options, this);
66
+
67
+ return (RightJS.Wrapper.Cache[RightJS.$uid(this._)] = this);
68
+ },
69
+
70
+ // protected
71
+
72
+ /**
73
+ * Catches the options
74
+ *
75
+ * @param Object user-options
76
+ * @param Element element with contextual options
77
+ * @return void
78
+ */
79
+ setOptions: function(options, element) {
80
+ if (element) {
81
+ options = RightJS.Object.merge(options, new Function("return "+(
82
+ element.get('data-'+ this.key) || '{}'
83
+ ))());
84
+ }
85
+
86
+ if (options) {
87
+ RightJS.Options.setOptions.call(this, RightJS.Object.merge(this.options, options));
88
+ }
89
+
90
+ return this;
91
+ }
92
+ });
93
+
94
+ /**
95
+ * Creating the actual widget class
96
+ *
97
+ */
98
+ var Klass = new RightJS.Class(AbstractWidget, methods);
99
+
100
+ // creating the widget related shortcuts
101
+ RightJS.Observer.createShortcuts(Klass.prototype, Klass.EVENTS || RightJS([]));
102
+
103
+ return Klass;
104
+ }
105
+
106
+
107
+ /**
108
+ * Sortable initialization script
109
+ *
110
+ * Copyright (C) 2010 Nikolay Nemshilov
111
+ */
112
+ var R = RightJS,
113
+ $ = RightJS.$,
114
+ $w = RightJS.$w,
115
+ isString = RightJS.isString,
116
+ isArray = RightJS.isArray,
117
+ Object = RightJS.Object;
118
+
119
+
120
+
121
+
122
+ /**
123
+ * The Sortable unit
124
+ *
125
+ * Copyright (C) 2009-2011 Nikolay Nemshilov
126
+ */
127
+ var Sortable = new Widget('UL', {
128
+ extend: {
129
+ version: '2.2.0',
130
+
131
+ EVENTS: $w('start change finish'),
132
+
133
+ Options: {
134
+ url: null, // the Xhr requests url address, might contain the '%{id}' placeholder
135
+ method: 'put', // the Xhr requests method
136
+
137
+ Xhr: {}, // additional Xhr options
138
+
139
+ idParam: 'id', // the id value name
140
+ posParam: 'position', // the position value name
141
+ parseId: true, // if the id attribute should be converted into an integer before sending
142
+
143
+ dragClass: 'dragging', // the in-process class name
144
+ accept: null, // a reference or a list of references to the other sortables between which you can drag the items
145
+ minLength: 1, // minimum number of items on the list when the feature works
146
+
147
+ itemCss: 'li', // the draggable item's css rule
148
+ handleCss: 'li', // the draggables handle element css rule
149
+
150
+ cssRule: '*[data-sortable]' // css-rule for automatically initializable sortables
151
+ },
152
+
153
+ current: false, // a reference to the currently active sortable
154
+
155
+ /**
156
+ * Typecasting the list element for Sortable
157
+ *
158
+ * @param Element list
159
+ * @return Sortable list
160
+ */
161
+ cast: function(element) {
162
+ element = $(element._);
163
+ if (!(element instanceof Sortable)) {
164
+ element = new Sortable(element);
165
+ }
166
+ return element;
167
+ }
168
+ },
169
+
170
+ /**
171
+ * basic constructor
172
+ *
173
+ * @param mixed element reference
174
+ * @param Object options
175
+ * @return void
176
+ */
177
+ initialize: function(element, options) {
178
+ this.$super('sortable', element)
179
+ .setOptions(options)
180
+ .addClass('rui-sortable')
181
+ .on('finish', this._tryXhr)
182
+ .on('selectstart', 'stopEvent'); // disable select under IE
183
+ },
184
+
185
+ /**
186
+ * some additional options processing
187
+ *
188
+ * @param Object options
189
+ * @param Element optional context
190
+ * @return Sortable this
191
+ */
192
+ setOptions: function(options, context) {
193
+ this.$super(options, context);
194
+
195
+ options = this.options;
196
+
197
+ // Preprocessing the acceptance list
198
+ var list = options.accept || [];
199
+ if (!isArray(list)) { list = [list]; }
200
+
201
+ options.accept = R([this].concat(list)).map($).uniq();
202
+
203
+ return this;
204
+ },
205
+
206
+ // returns a list of draggable items
207
+ items: function() {
208
+ return this.children(this.options.itemCss);
209
+ },
210
+
211
+ // protected
212
+
213
+ // starts the drag
214
+ startDrag: function(event) {
215
+ // don't let to drag out the last item
216
+ if (this.items().length <= this.options.minLength) { return; }
217
+
218
+ // trying to find the list-item upon which the user pressed the mouse
219
+ var item = event.find(this.options.itemCss),
220
+ handle = event.find(this.options.handleCss);
221
+
222
+ if (item && handle) {
223
+ this._initDrag(item, event.position());
224
+ Sortable.current = this;
225
+ this.fire('start', this._evOpts(event));
226
+ }
227
+ },
228
+
229
+ // moves the item
230
+ moveItem: function(event) {
231
+ var event_pos = event.position(),
232
+ item = this.itemClone._.style,
233
+ top = event_pos.y - this.yRDiff,
234
+ left = event_pos.x - this.xRDiff,
235
+ right = left + this.cloneWidth,
236
+ bottom = top + this.cloneHeight;
237
+
238
+ // moving the clone
239
+ item.top = (event_pos.y - this.yDiff) + 'px';
240
+ item.left = (event_pos.x - this.xDiff) + 'px';
241
+
242
+ // checking for an overlaping item
243
+ var over_item = this.suspects.first(function(suspect) {
244
+ return (
245
+ (top > suspect.top && top < suspect.topHalf) ||
246
+ (bottom < suspect.bottom && bottom > suspect.topHalf)
247
+ ) && (
248
+ (left > suspect.left && left < suspect.leftHalf) ||
249
+ (right < suspect.right && right > suspect.leftHalf)
250
+ );
251
+ });
252
+
253
+ if (over_item) {
254
+ item = over_item.item;
255
+ item.insert(this.item, item.prevSiblings().include(this.item) ? 'after' : 'before');
256
+ this._findSuspects();
257
+
258
+ this.fire('change', this._evOpts(event, item));
259
+ }
260
+ },
261
+
262
+ // finalizes the drag
263
+ finishDrag: function(event) {
264
+ if (this.itemClone) {
265
+ this.itemClone.remove();
266
+ this.item.setStyle('visibility:visible');
267
+ }
268
+ Sortable.current = false;
269
+ this.fire('finish', this._evOpts(event));
270
+ },
271
+
272
+ // returns the event options
273
+ _evOpts: function(event, item) {
274
+ item = item || this.item;
275
+ var list = Sortable.cast(item.parent());
276
+
277
+ return {
278
+ list: list,
279
+ item: item,
280
+ event: event,
281
+ index: list.items().indexOf(item)
282
+ };
283
+ },
284
+
285
+ _initDrag: function(item, event_pos) {
286
+ var dims = this.dimensions(), item_dims = item.dimensions();
287
+
288
+ // creating the draggable clone
289
+ var clone = item.clone().setStyle({
290
+ margin: 0,
291
+ zIndex: 9999,
292
+ position: 'absolute',
293
+ top: '0px',
294
+ left: '0px'
295
+ })
296
+ .addClass(this.options.dragClass).insertTo(this)
297
+ .setHeight(this.cloneHeight = item_dims.height)
298
+ .setWidth(this.cloneWidth = item_dims.width);
299
+
300
+ // adjusting the clone position to compensate relative fields and margins
301
+ var clone_pos = clone.position(),
302
+ real_x = item_dims.left - clone_pos.x,
303
+ real_y = item_dims.top - clone_pos.y;
304
+
305
+ clone.moveTo(real_x, real_y);
306
+
307
+ this.item = item.setStyle('visibility:hidden');
308
+ this.itemClone = clone;
309
+
310
+ // mouse event-position diffs
311
+ this.xDiff = event_pos.x - real_x;
312
+ this.yDiff = event_pos.y - real_y;
313
+ this.xRDiff = event_pos.x - clone.position().x;
314
+ this.yRDiff = event_pos.y - clone.position().y;
315
+
316
+ // collecting the list of interchangable items with their positions
317
+ this._findSuspects();
318
+ },
319
+
320
+ // collects the precached list of suspects
321
+ _findSuspects: function() {
322
+ var suspects = this.suspects = R([]), item = this.item, clone = this.itemClone;
323
+ this.options.accept.each(function(list) {
324
+ Sortable.cast(list).items().each(function(element) {
325
+ if (element !== item && element !== clone) {
326
+ var dims = element.dimensions();
327
+
328
+ // caching the sizes
329
+ suspects.push({
330
+ item: element,
331
+ top: dims.top,
332
+ left: dims.left,
333
+ right: dims.left + dims.width,
334
+ bottom: dims.top + dims.height,
335
+ topHalf: dims.top + dims.height/2,
336
+ leftHalf: dims.left + dims.width/2
337
+ });
338
+ }
339
+ });
340
+ });
341
+ },
342
+
343
+ // tries to send an Xhr request about the element relocation
344
+ _tryXhr: function(event) {
345
+ if (this.options.url) {
346
+ var url = R(this.options.url), params = {}, item = event.item, position = event.index + 1;
347
+
348
+ // building the Xhr request options
349
+ var options = Object.merge({
350
+ method: this.options.method,
351
+ params: {}
352
+ }, this.options.Xhr);
353
+
354
+ // grabbing the id
355
+ var id = item.get('id') || '';
356
+ if (this.options.parseId && id) {
357
+ id = (id.match(/\d+/) || [''])[0];
358
+ }
359
+
360
+ // assigning the parameters
361
+ if (url.include('%{id}')) {
362
+ url = url.replace('%{id}', id);
363
+ } else {
364
+ params[this.options.idParam] = id;
365
+ }
366
+ params[this.options.posParam] = position;
367
+
368
+ // merging the params with possible Xhr params
369
+ if (isString(options.params)) {
370
+ options.params += '&'+Object.toQueryString(params);
371
+ } else {
372
+ options.params = Object.merge(options.params, params);
373
+ }
374
+
375
+ // calling the server
376
+ RightJS.Xhr.load(url, options);
377
+ }
378
+ }
379
+ });
380
+
381
+
382
+ /**
383
+ * Document level hooks for sortables
384
+ *
385
+ * Copyright (C) 2009-2010 Nikolay Nemshilov
386
+ */
387
+ $(document).on({
388
+ mousedown: function(event) {
389
+ var element = event.find(Sortable.Options.cssRule+",*.rui-sortable");
390
+
391
+ if (element) {
392
+ Sortable.cast(element).startDrag(event);
393
+ }
394
+ },
395
+
396
+ mousemove: function(event) {
397
+ if (Sortable.current) {
398
+ Sortable.current.moveItem(event);
399
+ }
400
+ },
401
+
402
+ mouseup: function(event) {
403
+ if (Sortable.current) {
404
+ Sortable.current.finishDrag(event);
405
+ }
406
+ }
407
+ });
408
+
409
+ $(window).onBlur(function() {
410
+ if (Sortable.current) {
411
+ Sortable.current.finishDrag();
412
+ }
413
+ });
414
+
415
+
416
+ var embed_style = document.createElement('style'),
417
+ embed_rules = document.createTextNode(".rui-sortable{user-select:none;-moz-user-select:none;-webkit-user-select:none}");
418
+
419
+ embed_style.type = 'text/css';
420
+ document.getElementsByTagName('head')[0].appendChild(embed_style);
421
+
422
+ if(embed_style.styleSheet) {
423
+ embed_style.styleSheet.cssText = embed_rules.nodeValue;
424
+ } else {
425
+ embed_style.appendChild(embed_rules);
426
+ }
427
+
428
+
429
+ return Sortable;
430
+ })(document, RightJS);