puffer 0.0.32 → 0.1.0

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