puffer 0.0.7 → 0.0.8
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.
- data/VERSION +1 -1
- data/app/cells/puffer/base/additional.html.erb +13 -5
- data/app/helpers/puffer_helper.rb +6 -1
- data/app/views/layouts/puffer.html.erb +5 -3
- data/app/views/puffer/_form.html.erb +1 -1
- data/app/views/puffer/associated/one.js.erb +9 -0
- data/app/views/puffer/edit.html.erb +1 -1
- data/app/views/puffer/index.html.erb +7 -7
- data/app/views/puffer/new.html.erb +1 -1
- data/app/views/puffer/show.html.erb +4 -4
- data/lib/generators/puffer/install/templates/puffer/javascripts/application.js +10 -0
- data/lib/generators/puffer/install/templates/puffer/javascripts/rails-src.js +36 -378
- data/lib/generators/puffer/install/templates/puffer/javascripts/right-autocompleter-src.js +621 -0
- data/lib/generators/puffer/install/templates/puffer/javascripts/right-autocompleter.js +18 -0
- data/lib/generators/puffer/install/templates/puffer/javascripts/right-autocompleter.js.gz +0 -0
- data/lib/generators/puffer/install/templates/puffer/stylesheets/puffer.css +107 -6
- data/lib/puffer/base.rb +4 -3
- data/lib/puffer/controller/actions.rb +4 -70
- data/lib/puffer/controller/dsl.rb +23 -5
- data/lib/puffer/controller/generated.rb +65 -0
- data/lib/puffer/extensions/activerecord.rb +3 -3
- data/lib/puffer/extensions/core.rb +14 -0
- data/lib/puffer/extensions/mapper.rb +20 -0
- data/lib/puffer/fields.rb +11 -2
- data/lib/puffer/fields/field.rb +24 -1
- data/lib/puffer/inputs.rb +1 -3
- data/lib/puffer/inputs/association.rb +27 -1
- data/lib/puffer/inputs/base.rb +12 -4
- data/lib/puffer/inputs/boolean.rb +1 -1
- data/lib/puffer/inputs/date_time.rb +1 -1
- data/lib/puffer/resource.rb +1 -1
- data/lib/puffer/resource/routing.rb +2 -2
- data/lib/puffer/resource/scoping.rb +5 -1
- data/puffer.gemspec +15 -5
- data/spec/dummy/app/controllers/admin/profiles_controller.rb +2 -2
- data/spec/dummy/app/views/admin/users/index.html.erb +3 -1
- data/spec/dummy/config/database.yml +1 -1
- data/spec/dummy/public/puffer/javascripts/application.js +10 -0
- data/spec/dummy/public/puffer/javascripts/rails-src.js +36 -378
- data/spec/dummy/public/puffer/javascripts/right-autocompleter-src.js +621 -0
- data/spec/dummy/public/puffer/javascripts/right-autocompleter.js +18 -0
- data/spec/dummy/public/puffer/javascripts/right-autocompleter.js.gz +0 -0
- data/spec/dummy/public/puffer/stylesheets/puffer.css +107 -6
- data/spec/lib/extensions/core_spec.rb +29 -0
- data/spec/lib/resource/routing_spec.rb +11 -11
- metadata +28 -18
- data/lib/generators/puffer/install/templates/puffer/javascripts/rails.js +0 -14
- data/spec/dummy/public/puffer/javascripts/rails.js +0 -14
@@ -0,0 +1,18 @@
|
|
1
|
+
/**
|
2
|
+
* RightJS-UI: Autocompleter
|
3
|
+
* http://rightjs.org/ui/autocompleter
|
4
|
+
*
|
5
|
+
* Copyright (C) 2010 Nikolay Nemshilov
|
6
|
+
*/
|
7
|
+
var Autocompleter=RightJS.Autocompleter=function(h,c){function l(a,b,d,e){if(c.Fx)if(d===undefined){d=a.options.fxName;if(e===undefined){e={duration:a.options.fxDuration,onFinish:c(a.fire).bind(a,b)};if(b==="hide")e.duration=(c.Fx.Durations[e.duration]||e.duration)/2}}if(!c.Fx||!d)a.fire(b);return a.$super(d,e)}function m(a,b,d){var e=(this.reAnchor||(this.reAnchor=new c.Element("div",{"class":"rui-re-anchor"})).insert(this)).insertTo(a,"after").position(),f=a.dimensions(),i=parseInt(a.getStyle("borderTopWidth")),
|
8
|
+
j=parseInt(a.getStyle("borderLeftWidth")),q=parseInt(a.getStyle("borderRightWidth")),r=parseInt(a.getStyle("borderBottomWidth"));a=f.top-e.y+i;e=f.left-e.x+j;j=f.width-j-q;f=f.height-i-r;this.setStyle("visibility:hidden").show(null);if(b==="right")e+=j-this.size().x;else a+=f;this.moveTo(e,a);if(d)b==="left"||b==="right"?this.setHeight(f):this.setWidth(j);this.setStyle("visibility:visible").hide(null)}var g=c,n=c.$,s=c.$w,t=c.Xhr,o=c.RegExp,u=c.isArray,p=new c.Class(c.Element,{initialize:function(a){this.$super("div",
|
9
|
+
{"class":"rui-spinner"});this.dots=[];for(var b=0;b<(a||4);b++)this.dots.push(new c.Element("div"));this.dots[0].addClass("glowing");this.insert(this.dots);c(this.shift).bind(this).periodical(300)},shift:function(){if(this.visible()){var a=this.dots.pop();this.dots.unshift(a);this.insert(a,"top")}}}),k=new (function(a,b){if(!b){b=a;a="DIV"}var d=new c.Class(c.Element.Wrappers[a]||c.Element,{initialize:function(e,f){this.key=e;var i=[{"class":"rui-"+e}];this instanceof c.Input||this instanceof c.Form||
|
10
|
+
i.unshift(a);this.$super.apply(this,i);if(c.isString(f))f=c.$(f);if(f instanceof c.Element){this._=f._;if("$listeners"in f)f.$listeners=f.$listeners;f={}}this.setOptions(f,this);return c.Wrapper.Cache[c.$uid(this._)]=this},setOptions:function(e,f){f=f||this;c.Options.setOptions.call(this,c.Object.merge(e,eval("("+(f.get("data-"+this.key)||"{}")+")")));return this}});d=new c.Class(d,b);c.Observer.createShortcuts(d.prototype,d.EVENTS||[]);return d})("UL",{include:{show:function(a,b){this.constructor.current=
|
11
|
+
this;return l(this,"show",a,b)},hide:function(a,b){this.constructor.current=null;return l(this,"show",a,b)},showAt:function(a,b,d){this.hide(null).shownAt=a=c.$(a);m.call(this,a,b,d);return this.show()},toggleAt:function(a,b,d){return this.hidden()?this.showAt(a,b,d):this.hide()}},extend:{version:"2.2.0",EVENTS:s("show hide update load select done"),Options:{url:h.location.href,param:"search",method:"get",minLength:1,threshold:200,cache:true,local:null,fxName:"slide",fxDuration:"short",spinner:"native",
|
12
|
+
cssRule:"input[data-autocompleter]"}},initialize:function(a,b){this.input=n(a);this.$super("autocompleter",b).addClass("rui-dd-menu").onMousedown(this.clicked);this.input.autocompleter=this},destroy:function(){delete this.input.autocompleter;return this},prev:function(){return this.pick("prev")},next:function(){return this.pick("next")},done:function(a){if(a=a||this.first("li.current")){a.radioClass("current");this.input.setValue(g(a.html()).stripTags());this.fire("done")}return this.hide()},setOptions:function(a){this.$super(a,
|
13
|
+
this.input);a=this.options;g(a.url).includes("%{search}")||(a.url+=(g(a.url).includes("?")?"&":"?")+a.param+"=%{search}")},pick:function(a){var b=this.children(),d=b.first("hasClass","current"),e=b.indexOf(d);if(a=="prev")d=e<1?b.last():b[e<0?0:e-1];else if(a=="next")d=e<0||e==b.length-1?b.first():b[e+1];return this.fire("select",{item:d.radioClass("current")})},clicked:function(a){this.done(a.stop().find("li"))},keypressed:function(){if(this.input.value().length>=this.options.minLength){this.timeout&&
|
14
|
+
this.timeout.cancel();this.timeout=g(this.trigger).bind(this).delay(this.options.threshold)}else return this.hide()},trigger:function(){this.timeout=null;this.cache=this.cache||{};var a=this.input.value(),b=this.options;if(a.length<b.minLength)return this.hide();if(this.cache[a])this.suggest(this.cache[a],a);else if(u(b.local))this.suggest(this.findLocal(a),a);else this.request=t.load(b.url.replace("%{search}",encodeURIComponent(a)),{method:b.method,spinner:this.getSpinner(),onComplete:g(function(d){this.fire("load").suggest(d.text,
|
15
|
+
a)}).bind(this)})},suggest:function(a,b){if(this.options.cache)this.cache[b]=a;if(g(a).blank())this.hide();else{this.update(a.replace(/<ul[^>]*>|<\/ul>/im,""));this.fire("update");if(!this._connected||this.hidden()){this.showAt(this.input,"bottom","resize");this._connected=true}}return this},findLocal:function(a){var b=new o("("+o.escape(a)+")","ig");return g(this.options.local).map(function(d){if(d.match(b))return"<li>"+d.replace(b,"<strong>$1</strong>")+"</li>"}).compact().join("")},getSpinner:function(){var a=
|
16
|
+
this.options,b=a.spinner;if(b=="native"){b=a.spinner=(new p(3)).insertTo(this);b.addClass("rui-autocompleter-spinner")}b instanceof p&&m.call(b,this.input,"right","resize");return b}});n(h).on({focus:function(a){if((a=a.target)&&a instanceof c.Element&&(a.autocompleter||a.match(k.Options.cssRule)))a.autocompleter||new k(a)},blur:function(a){(a=a.target?a.target.autocompleter:null)&&a.visible()&&a.hide()},keydown:function(a){var b=a.target?a.target.autocompleter:null;if(b&&b.visible()){var d={27:"hide",
|
17
|
+
38:"prev",40:"next",13:"done"}[a.keyCode];if(d){a.stop();b[d]()}}},keyup:function(a){var b=a.target?a.target.autocompleter:null;b&&!g([9,27,37,38,39,40,13]).include(a.keyCode)&&b.keypressed(a)}});(function(){var a=h.createElement("style"),b=h.createTextNode(" *.rui-dd-menu, *.rui-dd-menu li{margin:0;padding:0;border:none;background:none;list-style:none;font-weight:normal;float:none} *.rui-dd-menu{display:none;position:absolute;z-index:9999;background:white;border:1px solid #BBB;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;box-shadow:#DDD .2em .2em .4em;-moz-box-shadow:#DDD .2em .2em .4em;-webkit-box-shadow:#DDD .2em .2em .4em} *.rui-dd-menu li{padding:.2em .4em;border-top:none;border-bottom:none;cursor:pointer} *.rui-dd-menu li.current{background:#DDD} *.rui-dd-menu li:hover{background:#EEE}dl.rui-dd-menu dt{padding:.3em .5em;cursor:default;font-weight:bold;font-style:italic;color:#444;background:#EEE}dl.rui-dd-menu dd li{padding-left:1.5em}div.rui-spinner,div.rui-spinner div{margin:0;padding:0;border:none;background:none;list-style:none;font-weight:normal;float:none;display:inline-block; *display:inline; *zoom:1;border-radius:.12em;-moz-border-radius:.12em;-webkit-border-radius:.12em}div.rui-spinner{text-align:center;white-space:nowrap;background:#EEE;border:1px solid #DDD;height:1.2em;padding:0 .2em}div.rui-spinner div{width:.4em;height:70%;background:#BBB;margin-left:1px}div.rui-spinner div:first-child{margin-left:0}div.rui-spinner div.glowing{background:#777}div.rui-re-anchor{margin:0;padding:0;background:none;border:none;float:none;display:inline;position:absolute;z-index:9999}.rui-autocompleter{border-top-color:#DDD !important;border-top-left-radius:0 !important;border-top-right-radius:0 !important;-moz-border-radius-topleft:0 !important;-moz-border-radius-topright:0 !important;-webkit-border-top-left-radius:0 !important;-webkit-border-top-right-radius:0 !important}.rui-autocompleter-spinner{border:none !important;background:none !important;position:absolute;z-index:9999}.rui-autocompleter-spinner div{margin-top:.2em !important; *margin-top:0.1em !important}");
|
18
|
+
a.type="text/css";if(a.styleSheet)a.styleSheet.cssText=b.nodeValue;else a.appendChild(b);h.getElementsByTagName("head")[0].appendChild(a)})();return k}(document,RightJS);
|
Binary file
|
@@ -88,7 +88,7 @@ h1
|
|
88
88
|
*display: inline;
|
89
89
|
zoom: 1;
|
90
90
|
color: #ddd;
|
91
|
-
padding:
|
91
|
+
padding: 7px 12px;
|
92
92
|
font-size: 11pt;
|
93
93
|
text-decoration: none;
|
94
94
|
text-shadow: #304759 -1px -1px 0;
|
@@ -120,6 +120,16 @@ h1
|
|
120
120
|
border-bottom-right-radius: 3px;
|
121
121
|
}
|
122
122
|
|
123
|
+
.sidebar .navigation li .additional dt
|
124
|
+
{
|
125
|
+
margin-bottom: 2px;
|
126
|
+
}
|
127
|
+
|
128
|
+
.sidebar .navigation li .additional dd
|
129
|
+
{
|
130
|
+
margin-bottom: 8px;
|
131
|
+
}
|
132
|
+
|
123
133
|
.columns
|
124
134
|
{
|
125
135
|
width: 100%;
|
@@ -170,7 +180,7 @@ h1
|
|
170
180
|
border-top-left-radius: 5px;
|
171
181
|
border-bottom-left-radius: 5px;
|
172
182
|
background: #fff;
|
173
|
-
padding:
|
183
|
+
padding: 30px;
|
174
184
|
}
|
175
185
|
|
176
186
|
.list_table
|
@@ -186,6 +196,11 @@ h1
|
|
186
196
|
-webkit-border-radius: 5px;
|
187
197
|
}
|
188
198
|
|
199
|
+
.list_table *
|
200
|
+
{
|
201
|
+
font-size: 8pt;
|
202
|
+
}
|
203
|
+
|
189
204
|
.list_table tr
|
190
205
|
{
|
191
206
|
vertical-align: top;
|
@@ -258,6 +273,40 @@ h1
|
|
258
273
|
background: #f4f4f4;
|
259
274
|
}
|
260
275
|
|
276
|
+
label, input, textarea
|
277
|
+
{
|
278
|
+
font-family: Helvetica, Arial, sans-serif;
|
279
|
+
}
|
280
|
+
|
281
|
+
input[type=text], input[type=password], textarea
|
282
|
+
{
|
283
|
+
border: #ccc solid 1px;
|
284
|
+
font-size: 11pt;
|
285
|
+
padding: 3px 0;
|
286
|
+
border-radius: 3px;
|
287
|
+
}
|
288
|
+
|
289
|
+
input[type=text]:focus, input[type=password]:focus, textarea:focus
|
290
|
+
{
|
291
|
+
border: #536C80 solid 1px;
|
292
|
+
}
|
293
|
+
|
294
|
+
input[type=submit]
|
295
|
+
{
|
296
|
+
border: 0;
|
297
|
+
border-radius: 3px;
|
298
|
+
background: #536C80;
|
299
|
+
color: #ddd;
|
300
|
+
text-shadow: -1px -1px 0 #304759;
|
301
|
+
padding: 3px 10px;
|
302
|
+
font-size: 11pt;
|
303
|
+
}
|
304
|
+
|
305
|
+
#search
|
306
|
+
{
|
307
|
+
width: 120px;
|
308
|
+
}
|
309
|
+
|
261
310
|
.form
|
262
311
|
{
|
263
312
|
margin-bottom: 30px;
|
@@ -269,21 +318,73 @@ h1
|
|
269
318
|
margin-bottom: 8px;
|
270
319
|
}
|
271
320
|
|
321
|
+
.form li .label
|
322
|
+
{
|
323
|
+
margin-bottom: 3px;
|
324
|
+
}
|
325
|
+
|
326
|
+
.form li .label *
|
327
|
+
{
|
328
|
+
display: inline;
|
329
|
+
}
|
330
|
+
|
272
331
|
.form li label
|
273
332
|
{
|
274
|
-
|
275
|
-
font-size: 11pt;
|
333
|
+
font-size: 10pt;
|
276
334
|
font-weight: bold;
|
277
335
|
}
|
278
336
|
|
279
337
|
.form li input[type=text], .form li input[type=password], .form li textarea
|
280
338
|
{
|
281
|
-
border: #ccc solid 1px;
|
282
339
|
width: 100%;
|
283
|
-
font-size: 12pt;
|
284
340
|
}
|
285
341
|
|
286
342
|
.form li textarea
|
287
343
|
{
|
288
344
|
height: 60px;
|
289
345
|
}
|
346
|
+
|
347
|
+
.field_error
|
348
|
+
{
|
349
|
+
color: #C83E3E;
|
350
|
+
}
|
351
|
+
|
352
|
+
.association
|
353
|
+
{
|
354
|
+
position: relative;
|
355
|
+
}
|
356
|
+
|
357
|
+
.association input[disabled]
|
358
|
+
{
|
359
|
+
text-indent: 25px;
|
360
|
+
}
|
361
|
+
|
362
|
+
.association .association_clear
|
363
|
+
{
|
364
|
+
position: absolute;
|
365
|
+
top: 4px;
|
366
|
+
left: 9px;
|
367
|
+
cursor: pointer;
|
368
|
+
display: none;
|
369
|
+
}
|
370
|
+
|
371
|
+
.association .association_clear:hover
|
372
|
+
{
|
373
|
+
color: #b00;
|
374
|
+
text-shadow: 1px 1px 2px #555;
|
375
|
+
}
|
376
|
+
|
377
|
+
.association input[disabled] ~ .association_clear
|
378
|
+
{
|
379
|
+
display: block;
|
380
|
+
}
|
381
|
+
|
382
|
+
.association .rui-autocompleter li .description
|
383
|
+
{
|
384
|
+
display: none;
|
385
|
+
}
|
386
|
+
|
387
|
+
.association .rui-autocompleter li:hover .description
|
388
|
+
{
|
389
|
+
display: block;
|
390
|
+
}
|
data/lib/puffer/base.rb
CHANGED
@@ -6,6 +6,7 @@ module Puffer
|
|
6
6
|
include Puffer::Controller::Helpers
|
7
7
|
include Puffer::Controller::Dsl
|
8
8
|
include Puffer::Controller::Config
|
9
|
+
include Puffer::Controller::Generated
|
9
10
|
|
10
11
|
respond_to :html, :js
|
11
12
|
|
@@ -28,19 +29,19 @@ module Puffer
|
|
28
29
|
def create
|
29
30
|
@record = resource.new_member
|
30
31
|
@record.save
|
31
|
-
respond_with @record, :location => resource.
|
32
|
+
respond_with @record, :location => resource.collection_path
|
32
33
|
end
|
33
34
|
|
34
35
|
def update
|
35
36
|
@record = resource.member
|
36
37
|
@record.update_attributes resource.attributes
|
37
|
-
respond_with @record, :location => resource.
|
38
|
+
respond_with @record, :location => resource.collection_path
|
38
39
|
end
|
39
40
|
|
40
41
|
def destroy
|
41
42
|
@record = resource.member
|
42
43
|
@record.destroy
|
43
|
-
redirect_to (request.referrer || resource.
|
44
|
+
redirect_to (request.referrer || resource.collection_path)
|
44
45
|
end
|
45
46
|
|
46
47
|
end
|
@@ -1,79 +1,13 @@
|
|
1
1
|
module Puffer
|
2
2
|
module Controller
|
3
|
-
|
3
|
+
class Actions < Array
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
%w(match get post put delete).each do |method|
|
6
|
+
define_method method do |*args|
|
7
|
+
push args.unshift(method)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
module ClassMethods
|
12
|
-
|
13
|
-
def generate_association_actions field
|
14
|
-
field.collection? ? generate_collection_association_actions(field) : generate_single_association_actions(field)
|
15
|
-
end
|
16
|
-
|
17
|
-
def generate_single_association_actions field
|
18
|
-
define_method "associated_#{field}_choosing" do
|
19
|
-
@record = model.find params[:id]
|
20
|
-
@records = field.association.klass.scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
|
21
|
-
@field = field
|
22
|
-
render 'puffer/associated/one'
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def generate_collection_association_actions field
|
27
|
-
define_method "associated_#{field}" do
|
28
|
-
@record = model.find params[:id]
|
29
|
-
@records = field.association.klass.scoped(:conditions => {:id => params[:ids]}).scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
|
30
|
-
@field = field
|
31
|
-
render 'puffer/associated/many'
|
32
|
-
end
|
33
|
-
|
34
|
-
define_method "associated_#{field}_choosing" do
|
35
|
-
@record = model.find params[:id]
|
36
|
-
@records = field.association.klass.scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
|
37
|
-
@choosen = field.association.klass.scoped(:conditions => {:id => params[:ids]}).scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
|
38
|
-
@field = field
|
39
|
-
render 'puffer/associated/many'
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def generate_change_actions field
|
44
|
-
define_method "toggle_#{field}" do
|
45
|
-
@record = model.find params[:id]
|
46
|
-
@field = field
|
47
|
-
@record.toggle! field.name.to_sym
|
48
|
-
render 'puffer/toggle'
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
53
|
-
|
54
|
-
def route_member_actions
|
55
|
-
unless @route_member_actions
|
56
|
-
@route_member_actions = {}
|
57
|
-
actions.each do |action|
|
58
|
-
@route_member_actions.merge!(action => :get)
|
59
|
-
end
|
60
|
-
[:form_fields, :update_fields, :create_fields].each do |fields|
|
61
|
-
fields = send fields
|
62
|
-
fields.each do |field|
|
63
|
-
if field.association?
|
64
|
-
field.collection? ? @route_member_actions.merge!("associated_#{field}" => :get, "associated_#{field}_choosing" => :get) : @route_member_actions.merge!("associated_#{field}_choosing" => :get)
|
65
|
-
end
|
66
|
-
end if fields
|
67
|
-
end
|
68
|
-
index_fields.each do |field|
|
69
|
-
@route_member_actions.merge!("toggle_#{field}" => :post) if field.toggable?
|
70
|
-
end if index_fields
|
71
|
-
end
|
72
|
-
@route_member_actions
|
73
|
-
end
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
11
|
end
|
78
12
|
end
|
79
13
|
end
|
@@ -10,26 +10,44 @@ module Puffer
|
|
10
10
|
|
11
11
|
%w(index show form create update).each do |action|
|
12
12
|
class_attribute "_#{action}_fields"
|
13
|
-
send "_#{action}_fields=", Puffer::Fields.new unless send("_#{action}_fields")
|
13
|
+
send "_#{action}_fields=", Puffer::Fields.new unless send("_#{action}_fields?")
|
14
14
|
helper_method "#{action}_fields"
|
15
15
|
end
|
16
|
+
|
17
|
+
class_attribute :_members
|
18
|
+
self._members = Puffer::Controller::Actions.new
|
19
|
+
class_attribute :_collections
|
20
|
+
self._collections = Puffer::Controller::Actions.new
|
16
21
|
end
|
17
22
|
end
|
18
23
|
|
19
24
|
module ClassMethods
|
20
25
|
|
26
|
+
def inherited klass
|
27
|
+
klass._members = _members.dup
|
28
|
+
klass._collections = _collections.dup
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def member &block
|
33
|
+
block.bind(_members).call if block_given?
|
34
|
+
end
|
35
|
+
|
36
|
+
def collection &block
|
37
|
+
block.bind(_collections).call if block_given?
|
38
|
+
end
|
39
|
+
|
21
40
|
%w(index show form create update).each do |action|
|
22
41
|
define_method action do |&block|
|
23
|
-
@_fields = send
|
24
|
-
@_fields.clear
|
42
|
+
@_fields = send("_#{action}_fields=", Puffer::Fields.new)
|
25
43
|
block.call if block
|
26
|
-
|
44
|
+
remove_instance_variable :@_fields
|
27
45
|
end
|
28
46
|
end
|
29
47
|
|
30
48
|
def field name, options = {}
|
31
49
|
field = @_fields.field(model, name, options) if @_fields
|
32
|
-
|
50
|
+
generate_association_actions field if field.reflection
|
33
51
|
#generate_change_actions field if field.toggable?
|
34
52
|
end
|
35
53
|
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Puffer
|
2
|
+
module Controller
|
3
|
+
module Generated
|
4
|
+
|
5
|
+
def self.included base
|
6
|
+
base.class_eval do
|
7
|
+
extend ClassMethods
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
|
13
|
+
def generate_association_actions field
|
14
|
+
field.collection? ? generate_collection_association_actions(field) : generate_single_association_actions(field)
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate_single_association_actions field
|
18
|
+
define_method "associated_#{field}_choosing" do
|
19
|
+
@field = field
|
20
|
+
@record = resource.member if params[:id]
|
21
|
+
@records = field.reflection.klass.includes(field.association_fields.includes).joins(field.association_fields.includes).where(field.association_fields.searches(params[:search])).limit(100).all
|
22
|
+
render 'puffer/associated/one'
|
23
|
+
end
|
24
|
+
|
25
|
+
collection do
|
26
|
+
get "associated_#{field}_choosing"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_collection_association_actions field
|
31
|
+
define_method "associated_#{field}" do
|
32
|
+
@record = resource.member
|
33
|
+
@records = field.association.klass.scoped(:conditions => {:id => params[:ids]}).scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
|
34
|
+
@field = field
|
35
|
+
render 'puffer/associated/many'
|
36
|
+
end
|
37
|
+
|
38
|
+
define_method "associated_#{field}_choosing" do
|
39
|
+
@record = resource.member
|
40
|
+
@records = field.association.klass.scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
|
41
|
+
@choosen = field.association.klass.scoped(:conditions => {:id => params[:ids]}).scoped(:conditions => search_query(field.association_fields)).paginate(:page => params[:page], :include => includes(field.association_fields))
|
42
|
+
@field = field
|
43
|
+
render 'puffer/associated/many'
|
44
|
+
end
|
45
|
+
|
46
|
+
collection do
|
47
|
+
get "associated_#{field}"
|
48
|
+
get "associated_#{field}_choosing"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def generate_change_actions field
|
53
|
+
define_method "toggle_#{field}" do
|
54
|
+
@record = model.find params[:id]
|
55
|
+
@field = field
|
56
|
+
@record.toggle! field.name.to_sym
|
57
|
+
render 'puffer/toggle'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -8,11 +8,11 @@ module Puffer
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def to_title
|
11
|
-
send
|
11
|
+
send title_method
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
self.class.column_names[1].to_sym
|
14
|
+
def title_method
|
15
|
+
self.class.column_names.detect {|c| c =~ /name|title/} || self.class.column_names[1].to_sym
|
16
16
|
end
|
17
17
|
|
18
18
|
end
|
@@ -21,11 +21,25 @@ module Puffer
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
module Array
|
25
|
+
def to_includes
|
26
|
+
map do |field|
|
27
|
+
sections = field.split('.').map(&:to_sym)
|
28
|
+
hash = sections.pop
|
29
|
+
sections.reverse_each do |section|
|
30
|
+
hash = {section => hash}
|
31
|
+
end
|
32
|
+
hash
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
24
37
|
end
|
25
38
|
end
|
26
39
|
|
27
40
|
String.send :include, Puffer::Extensions::String
|
28
41
|
Symbol.send :include, Puffer::Extensions::Symbol
|
42
|
+
Array.send :include, Puffer::Extensions::Array
|
29
43
|
|
30
44
|
Kernel.class_eval do
|
31
45
|
def swallow_nil
|