autoforme 1.9.1 → 1.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7d0bdcb16302f8c39805290a5f31dc4e6317aacb91eea042662d949fe5688c6f
4
- data.tar.gz: 3e9d217d00951f5bb008d6278ec2642fb6a2f1cc2a6511d8a76cfb3f71c1a46d
3
+ metadata.gz: '08b9c95c4e096845f520e6543543f644d9fc7f558ae6c8674ac508a5a392e18a'
4
+ data.tar.gz: 51b362ce883daf920aaa4035d1f5cd2073b96c78f54aad0c1411308d08b794d7
5
5
  SHA512:
6
- metadata.gz: 3f8701563f00846a37ad405852ef015c4c24c8634e7a5ecf2e28844fca78dee54c3b46cda1d3e7747eb40b8f5e3ed93df1c703c9c3d933cb0e7f4a8d485f592f
7
- data.tar.gz: e54401c38c27521d6d55ac706bdd0d1867c4adf15771b38f6ce4ce364b20ff6b01715a9b37195e5e1df571de866ae91f005b085e3b4de93d492f2351b758a79b
6
+ metadata.gz: b9ed3dece202d2d48cc6b65746ba979acc57d3b1f67843b4d123d531313162bbf5806c1200ce9bce932eef9dd3aefd7ba1ff6582083b99dc171c8fb90e725c16
7
+ data.tar.gz: 7ad255b23d6ebbf43b6ff5caf43c7772b40386451aed7cfe456a09707b05b849e41bb763fe58f7df91940987602cf11972f41e9237b7d49c2ca554d55621769d
data/CHANGELOG CHANGED
@@ -1,3 +1,29 @@
1
+ === 1.12.0 (2022-06-29)
2
+
3
+ * Handle autocomplete queries with an empty query by returning empty string (jeremyevans)
4
+
5
+ * Switch autocomplete support to depend on Pixabay/JavaScript-autoComplete (jeremyevans)
6
+
7
+ * Make autoforme.js file no longer require JQuery (jeremyevans)
8
+
9
+ * Make navigation tab li tag use nav-item, for Bootstrap 5 compatibility (jeremyevans)
10
+
11
+ === 1.11.0 (2021-11-30)
12
+
13
+ * Require forme 2.0.0 (jeremyevans)
14
+
15
+ * Add support for view_options framework option (nmb, jeremyevans) (#42)
16
+
17
+ * Drop support for Ruby 1.8 (jeremyevans)
18
+
19
+ === 1.10.0 (2021-08-27)
20
+
21
+ * Do not consider read_only many_to_many associations to be editable (jeremyevans)
22
+
23
+ * Ignore unique constraint violations when adding associated objects in mtm_update (jeremyevans)
24
+
25
+ * Handle search fields that cannot be typecast correctly by returning no results (jeremyevans)
26
+
1
27
  === 1.9.1 (2019-07-22)
2
28
 
3
29
  * [SECURITY] Escape object display name when displaying association links (adam12)
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013-2018 Jeremy Evans
1
+ Copyright (c) 2013-2021 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to
data/README.rdoc CHANGED
@@ -6,12 +6,7 @@ integrate easily into web frameworks, and currently supports
6
6
  Roda, Sinatra, and Rails. The only currently supported ORM is
7
7
  Sequel::Model.
8
8
 
9
- AutoForme's UI and capabilities are modeled on
10
- scaffolding_extensions [2], though AutoForme is considerably more
11
- flexible in terms of configuration.
12
-
13
9
  1. https://github.com/jeremyevans/forme
14
- 2. https://github.com/jeremyevans/scaffolding_extensions
15
10
 
16
11
  = Installation
17
12
 
@@ -22,8 +17,7 @@ flexible in terms of configuration.
22
17
  Demo Site :: http://autoforme-demo.jeremyevans.net
23
18
  RDoc :: http://autoforme.jeremyevans.net
24
19
  Source :: https://github.com/jeremyevans/autoforme
25
- IRC :: irc://irc.freenode.net/forme
26
- Google Group :: https://groups.google.com/forum/#!forum/ruby-forme
20
+ Discussion Forum :: https://github.com/jeremyevans/autoforme/discussions
27
21
  Bug Tracker :: https://github.com/jeremyevans/autoforme/issues
28
22
 
29
23
  = Features
@@ -161,12 +155,13 @@ These options are related to displayed output:
161
155
 
162
156
  form_attributes :: Hash of attributes to use for any form tags
163
157
  form_options :: Hash of Forme::Form options to pass for any forms created
164
- class_display_name :: The string to use when referring to the model class
158
+ class_display_name :: The string to use on pages when referring to the model class.
159
+ This defaults to the full class name.
165
160
  display_name :: The string to use when referring to a model instance. Can either be a symbol
166
161
  representing an instance method call, or a Proc called with the model object,
167
162
  the model object and type symbol, or the model object, type symbol, and request,
168
163
  depending on the arity of the Proc.
169
- link_name :: The string to use in links for the class
164
+ link_name :: The string to use in links for the class. This defaults to +class_display_name+.
170
165
  edit_html :: The html to use for a particular object edit field. Should be a proc that takes the
171
166
  model object, column symbol, type symbol, and request and returns the html to use.
172
167
  page_footer :: Override the default footer used for pages
@@ -174,6 +169,8 @@ page_header :: Override the default header used for pages
174
169
  show_html :: The html to use for displaying the value for an object field. Should be a proc that takes the
175
170
  model object, column symbol, type symbol, and request and returns the html to use.
176
171
  table_class :: The html class string to use for the browse and search tables
172
+ view_options :: Hash with options passed when rendering the view (how these options are used varies
173
+ in each of the supported web frameworks), e.g. <tt>view_options: {:layout => :formelayout}</tt>
177
174
 
178
175
  These hook options should be callable objects that are called with the model object and the request.
179
176
 
@@ -212,9 +209,12 @@ AutoForme also has javascript support for the progressive enhancement of the fol
212
209
  * Loading association links via ajax if lazy_load_association_links is true.
213
210
  * Adding and removing many-to-many associated objects via ajax for inline_mtm_associations
214
211
 
215
- AutoForme's javascript support is contained in the autoforme.js file in the root
216
- of the distribution. AutoForme's autocompleting support also requires
217
- https://github.com/dyve/jquery-autocomplete
212
+ AutoForme's javascript support is contained in the +autoforme.js+ file in the root
213
+ of the repository. AutoForme's autocompleting support also requires
214
+ https://github.com/Pixabay/JavaScript-autoComplete
215
+
216
+ Make sure to load the +autoforme.js+ file after the DOM content has been loaded, such
217
+ as at the end of the body.
218
218
 
219
219
  = Reloading Code
220
220
 
@@ -238,6 +238,66 @@ use AutoForme in Rails development mode. The best way to handle it is to call
238
238
  +AutoForme.for+ in the related controller file, and have an initializer reference
239
239
  the controller class, causing the controller file to be loaded.
240
240
 
241
+ = Roda
242
+
243
+ Because Roda uses a routing tree, unlike Rails and Sinatra, with Roda you need to
244
+ dispatch to the autoforme routes at the point in the routing tree where you want
245
+ to mount them. Additionally, the Roda support offers a Roda plugin for easier
246
+ configuration.
247
+
248
+ To mount the autoforme routes in the root of the application, you could do:
249
+
250
+ class App < Roda
251
+ plugin :autoforme do
252
+ model Artist
253
+ end
254
+
255
+ route do
256
+ # rest of routing tree
257
+ autoforme
258
+ end
259
+ end
260
+
261
+ To mount the routes in a subpath:
262
+
263
+ class App < Roda
264
+ plugin :autoforme do
265
+ model Artist
266
+ end
267
+
268
+ route do
269
+ r.on "admin" do
270
+ autoforme
271
+ end
272
+
273
+ # rest of routing tree
274
+ end
275
+ end
276
+
277
+ To handle multiple autoforme configurations, mounted at different subpaths:
278
+
279
+ class App < Roda
280
+ plugin :autoforme
281
+
282
+ autoforme(name: 'artists') do
283
+ model Artist
284
+ end
285
+ autoforme(name: 'albums') do
286
+ model Album
287
+ end
288
+
289
+ route do
290
+ r.on "artists" do
291
+ autoforme('artists')
292
+ end
293
+ r.on "albums" do
294
+ autoforme('albums')
295
+ end
296
+
297
+ # rest of routing tree
298
+ end
299
+ end
300
+
241
301
  = TODO
242
302
 
243
303
  * capybara-webkit tests for ajax behavior
data/autoforme.js CHANGED
@@ -1,81 +1,122 @@
1
- var ready = function() {
2
- var autoforme = $('#autoforme_content');
3
- var base_url = autoforme.data('url');
1
+ (function() {
2
+ var autoforme = document.querySelector('#autoforme_content');
3
+ if (!autoforme) {
4
+ return;
5
+ }
6
+ var base_url = autoforme.getAttribute('data-url');
7
+ var xhr_headers = {'X-Requested-With': 'XMLHttpRequest'};
4
8
 
5
- function autoforme_fix_autocomplete(e) {
6
- $(e).find('.autoforme_autocomplete').each(function(){
7
- $(this).val($(this).val().split(' - ', 2)[0]);
9
+ function autoforme_fix_autocomplete(form) {
10
+ form.querySelectorAll('.autoforme_autocomplete').forEach((e) => {
11
+ e.value = e.value.split(' - ', 2)[0];
8
12
  });
9
13
  }
10
14
 
11
- function autoforme_setup_autocomplete() {
12
- autoforme.find('.autoforme_autocomplete').each(function(){
13
- var e = $(this);
14
- var column = e.data('column');
15
- var exclude = e.data('exclude');
15
+ function autoforme_setup_autocomplete(content) {
16
+ content.querySelectorAll('.autoforme_autocomplete').forEach((e) => {
17
+ var column = e.getAttribute('data-column');
18
+ var exclude = e.getAttribute('data-exclude');
16
19
  var url = base_url + 'autocomplete';
17
20
  if (column) {
18
21
  url += '/' + column;
19
22
  }
20
- url += '?type=' + e.data('type');
23
+ url += '?type=' + e.getAttribute('data-type');
21
24
  if (exclude) {
22
25
  url += '&exclude=' + exclude;
23
26
  }
24
- e.autocomplete(url);
27
+
28
+ new autoComplete({
29
+ selector: '[id="'+e.getAttribute("id")+'"]',
30
+ source: function(term, suggest) {
31
+ fetch((url + '&q=' + term), {headers: xhr_headers}).
32
+ then(function(response) {
33
+ return response.text();
34
+ }).
35
+ then(function(body) {
36
+ suggest(body.split("\n"));
37
+ });
38
+ }
39
+ });
25
40
  });
26
41
  }
27
42
 
28
- autoforme_setup_autocomplete();
43
+ autoforme_setup_autocomplete(autoforme);
29
44
 
30
- autoforme.on('submit', 'form', function(e){
31
- autoforme_fix_autocomplete(this);
45
+ autoforme.querySelectorAll("form").forEach((form) => {
46
+ form.addEventListener('submit', function(){
47
+ autoforme_fix_autocomplete(form);
48
+ }, {passive: true});
32
49
  });
33
50
 
51
+ var lazy_load_association_links = autoforme.querySelector('#lazy_load_association_links');
52
+ if (lazy_load_association_links) {
53
+ load_association_links = function(e) {
54
+ e.preventDefault();
55
+ lazy_load_association_links.removeEventListener('click', load_association_links);
34
56
 
35
- $('#lazy_load_association_links').click(function(e){
36
- var t = $(this);
37
- t.load(base_url + "association_links/" + t.data('object') + "?type=" + t.data('type'), autoforme_setup_autocomplete);
38
- t.unbind('click');
39
- e.preventDefault();
40
- });
57
+ var url = base_url + "association_links/" + load_association_links.getAttribute('data-object') + "?type=" + load_association_links.getAttribute('data-type');
58
+ fetch(url, {headers: xhr_headers}).
59
+ then(function(response) {
60
+ return response.text();
61
+ }).
62
+ then(function(body) {
63
+ lazy_load_association_links.innerHTML = body;
64
+ autoforme_setup_autocomplete(lazy_load_association_links);
65
+ });
66
+ };
67
+ lazy_load_association_links.addEventListener('click', load_association_links);
68
+ }
41
69
 
42
- autoforme.on('submit', '.mtm_add_associations', function(e){
43
- var form = $(this);
44
- if (form.find('.autoforme_autocomplete').length == 0) {
45
- var select = form.find('select')[0];
46
- $.post(this.action, form.serialize(), function(data, textStatus){
47
- $(select).find('option:selected').remove();
48
- select.selectedIndex = 0;
49
- $(form.data('remove')).append(data);
50
- });
51
- } else {
52
- autoforme_fix_autocomplete(form);
53
- $.post(this.action, form.serialize(), function(data, textStatus){
54
- var t = form.find('.autoforme_autocomplete');
55
- t.val('');
56
- t.data('autocompleter').cacheFlush();
57
- $(form.data('remove')).append(data);
70
+ setup_remove_hooks = function() {
71
+ autoforme.querySelectorAll('.inline_mtm_remove_associations form.mtm_remove_associations').forEach((form) => {
72
+ if (form.remove_hook_setup) {return;}
73
+ form.remove_hook_setup = true;
74
+
75
+ form.addEventListener('submit', function(e){
76
+ fetch(form.action, {method: 'post', body: new FormData(form), headers: xhr_headers}).
77
+ then(function(response) {
78
+ return response.text();
79
+ }).
80
+ then(function(body) {
81
+ document.querySelector(form.getAttribute('data-add')).insertAdjacentHTML('beforeend', body);
82
+ form.parentElement.remove();
83
+ });
84
+ e.preventDefault();
58
85
  });
59
- }
60
- e.preventDefault();
61
- });
86
+ });
87
+ };
88
+ setup_remove_hooks();
89
+
90
+ autoforme.querySelectorAll('.mtm_add_associations').forEach((form) => {
91
+ form.addEventListener('submit', function(e){
92
+ var form_ac = form.querySelector('.autoforme_autocomplete');
93
+ if (!form_ac) {
94
+ var select = form.querySelector('select');
62
95
 
63
- autoforme.on('submit', '.inline_mtm_remove_associations form', function(e){
64
- var form = $(this);
65
- var parent = form.parent();
66
- $.post(this.action, form.serialize(), function(data, textStatus){
67
- var t = $(form.data('add'));
68
- if (t[0].type == "text") {
69
- t.data('autocompleter').cacheFlush();
96
+ fetch(form.action, {method: 'post', body: new FormData(form), headers: xhr_headers}).
97
+ then(function(response) {
98
+ return response.text();
99
+ }).
100
+ then(function(body) {
101
+ select.remove(select.selectedIndex);
102
+ select.selectedIndex = 0;
103
+ document.querySelector(form.getAttribute('data-remove')).insertAdjacentHTML('beforeend', body);
104
+ setup_remove_hooks();
105
+ });
70
106
  } else {
71
- t.append(data);
107
+ autoforme_fix_autocomplete(form);
108
+
109
+ fetch(form.action, {method: 'post', body: new FormData(form), headers: xhr_headers}).
110
+ then(function(response) {
111
+ return response.text();
112
+ }).
113
+ then(function(body) {
114
+ form_ac.value = '';
115
+ document.querySelector(form.getAttribute('data-remove')).insertAdjacentHTML('beforeend', body);
116
+ setup_remove_hooks();
117
+ });
72
118
  }
73
- parent.remove();
119
+ e.preventDefault();
74
120
  });
75
- e.preventDefault();
76
121
  });
77
- };
78
-
79
-
80
- $(document).ready(ready);
81
- $(document).on('page:load', ready);
122
+ })();
@@ -87,9 +87,7 @@ module AutoForme
87
87
  else
88
88
  return false unless model.supported_action?(normalized_type, request)
89
89
 
90
- if title = TITLE_MAP[@normalized_type]
91
- @title = "#{model.class_name} - #{title}"
92
- end
90
+ @title = "#{model.class_name} - #{TITLE_MAP[@normalized_type]}"
93
91
  end
94
92
 
95
93
  true
@@ -134,7 +132,7 @@ module AutoForme
134
132
  type.to_s
135
133
  when :edit
136
134
  "edit/#{model.primary_key_value(obj)}"
137
- when :mtm_edit
135
+ else # when :mtm_edit
138
136
  "mtm_edit/#{model.primary_key_value(obj)}?association=#{params_association}"
139
137
  end
140
138
  path = url_for(path)
@@ -195,7 +193,7 @@ module AutoForme
195
193
  content << '<ul class="nav nav-tabs">'
196
194
  Model::DEFAULT_SUPPORTED_ACTIONS.each do |action_type|
197
195
  if model.supported_action?(action_type, request)
198
- content << "<li class=\"#{'active' if type == action_type}\"><a href=\"#{url_for(action_type)}\">#{tab_name(action_type)}</a></li>"
196
+ content << "<li class=\"nav-item #{'active' if type == action_type}\"><a class=\"nav-link\" href=\"#{url_for(action_type)}\">#{tab_name(action_type)}</a></li>"
199
197
  end
200
198
  end
201
199
  content << '</ul>'
@@ -227,10 +225,15 @@ module AutoForme
227
225
  # Options to use for the form. If the form uses POST, automatically adds the CSRF token.
228
226
  def form_opts(action=nil)
229
227
  opts = model.form_options_for(type, request).dup
230
- hidden_tags = opts[:hidden_tags] = []
231
- if csrf = request.csrf_token_hash(action)
232
- hidden_tags << lambda{|tag| csrf if (tag.attr[:method] || tag.attr['method']).to_s.upcase == 'POST'}
228
+
229
+ opts[:_before_post] = lambda do |form|
230
+ if csrf_hash = request.csrf_token_hash(action)
231
+ csrf_hash.each do |name, value|
232
+ form.tag(:input, :type=>:hidden, :name=>name, :value=>value)
233
+ end
234
+ end
233
235
  end
236
+
234
237
  opts
235
238
  end
236
239
 
@@ -310,19 +313,19 @@ module AutoForme
310
313
  if html = model.show_html_for(obj, column, type, request)
311
314
  col_opts = col_opts.merge(:html=>html)
312
315
  end
313
- t << f.input(column, col_opts).to_s
316
+ t << f.input(column, col_opts)
314
317
  end
315
318
  t << '</table>'
316
319
  if type == :show && model.supported_action?(:edit, request)
317
320
  t << Forme.form(form_attributes(:action=>url_for("edit/#{model.primary_key_value(obj)}")), form_opts) do |f1|
318
321
  f1.button(:value=>'Edit', :class=>'btn btn-primary')
319
- end.to_s
322
+ end
320
323
  end
321
324
  if type == :delete
322
325
  form_attr = form_attributes(:action=>url_for("destroy/#{model.primary_key_value(obj)}"), :method=>:post)
323
326
  t << Forme.form(form_attr, form_opts(form_attr[:action])) do |f1|
324
327
  f1.button(:value=>'Delete', :class=>'btn btn-danger')
325
- end.to_s
328
+ end
326
329
  else
327
330
  t << association_links(obj)
328
331
  end
@@ -353,11 +356,11 @@ module AutoForme
353
356
  f.input(column, col_opts)
354
357
  end
355
358
  f.button(:value=>'Update', :class=>'btn btn-primary')
356
- end.to_s
359
+ end
357
360
  if model.supported_action?(:delete, request)
358
361
  t << Forme.form(form_attributes(:action=>url_for("delete/#{model.primary_key_value(obj)}")), form_opts) do |f|
359
362
  f.button(:value=>'Delete', :class=>'btn btn-danger')
360
- end.to_s
363
+ end
361
364
  end
362
365
  t << association_links(obj)
363
366
  end
@@ -487,15 +490,15 @@ module AutoForme
487
490
  opts = model.column_options_for(:mtm_edit, request, assoc)
488
491
  add_opts = opts[:add] ? opts.merge(opts.delete(:add)) : opts
489
492
  remove_opts = opts[:remove] ? opts.merge(opts.delete(:remove)) : opts
490
- add_opts = {:name=>'add[]', :id=>'add', :label=>'Associate With'}.merge(add_opts)
493
+ add_opts = {:name=>'add[]', :id=>'add', :label=>'Associate With'}.merge!(add_opts)
491
494
  if model.association_autocomplete?(assoc, request)
492
- f.input(assoc, {:type=>'text', :class=>'autoforme_autocomplete', :attr=>{'data-type'=>'association', 'data-column'=>assoc, 'data-exclude'=>model.primary_key_value(obj)}, :value=>''}.merge(add_opts))
495
+ f.input(assoc, {:type=>'text', :class=>'autoforme_autocomplete', :attr=>{'data-type'=>'association', 'data-column'=>assoc, 'data-exclude'=>model.primary_key_value(obj)}, :value=>''}.merge!(add_opts))
493
496
  else
494
- f.input(assoc, {:dataset=>model.unassociated_mtm_objects(request, assoc, obj), :size=>10}.merge(add_opts))
497
+ f.input(assoc, {:dataset=>model.unassociated_mtm_objects(request, assoc, obj), :size=>10}.merge!(add_opts))
495
498
  end
496
- f.input(assoc, {:name=>'remove[]', :id=>'remove', :label=>'Disassociate From', :dataset=>model.associated_mtm_objects(request, assoc, obj), :value=>[], :size=>10}.merge(remove_opts))
499
+ f.input(assoc, {:name=>'remove[]', :id=>'remove', :label=>'Disassociate From', :dataset=>model.associated_mtm_objects(request, assoc, obj), :value=>[], :size=>10}.merge!(remove_opts))
497
500
  f.button(:value=>'Update', :class=>'btn btn-primary')
498
- end.to_s
501
+ end
499
502
  end
500
503
  else
501
504
  page do
@@ -540,7 +543,9 @@ module AutoForme
540
543
 
541
544
  # Handle autocomplete action by returning a string with one line per model object.
542
545
  def handle_autocomplete
543
- unless (query = request.params['q'].to_s).empty?
546
+ if (query = request.params['q'].to_s).empty?
547
+ ''
548
+ else
544
549
  model.autocomplete(:type=>@subtype, :request=>request, :association=>params_association, :query=>query, :exclude=>request.params['exclude']).join("\n")
545
550
  end
546
551
  end
@@ -648,14 +653,14 @@ module AutoForme
648
653
  t << Forme.form(obj, form_attr, form_opts(form_attr[:action])) do |f|
649
654
  opts = model.column_options_for(:mtm_edit, request, assoc)
650
655
  add_opts = opts[:add] ? opts.merge(opts.delete(:add)) : opts.dup
651
- add_opts = {:name=>'add[]', :id=>"add_#{assoc}"}.merge(add_opts)
656
+ add_opts = {:name=>'add[]', :id=>"add_#{assoc}"}.merge!(add_opts)
652
657
  if model.association_autocomplete?(assoc, request)
653
- f.input(assoc, {:type=>'text', :class=>'autoforme_autocomplete', :attr=>{'data-type'=>'association', 'data-column'=>assoc, 'data-exclude'=>model.primary_key_value(obj)}, :value=>''}.merge(add_opts))
658
+ f.input(assoc, {:type=>'text', :class=>'autoforme_autocomplete', :attr=>{'data-type'=>'association', 'data-column'=>assoc, 'data-exclude'=>model.primary_key_value(obj)}, :value=>''}.merge!(add_opts))
654
659
  else
655
- f.input(assoc, {:dataset=>model.unassociated_mtm_objects(request, assoc, obj), :multiple=>false, :add_blank=>true}.merge(add_opts))
660
+ f.input(assoc, {:dataset=>model.unassociated_mtm_objects(request, assoc, obj), :multiple=>false, :add_blank=>true}.merge!(add_opts))
656
661
  end
657
662
  f.button(:value=>'Add', :class=>'btn btn-xs btn-primary')
658
- end.to_s
663
+ end
659
664
  end
660
665
  t << "</div>"
661
666
  t << "<div class='inline_mtm_remove_associations'><ul>"
@@ -680,7 +685,7 @@ module AutoForme
680
685
  form_attr = form_attributes(:action=>url_for("mtm_update/#{model.primary_key_value(obj)}?association=#{assoc}&remove%5b%5d=#{model.primary_key_value(assoc_obj)}&redir=edit"), :method=>'post', :class => 'mtm_remove_associations', 'data-add'=>"#add_#{assoc}")
681
686
  t << Forme.form(form_attr, form_opts(form_attr[:action])) do |f|
682
687
  f.button(:value=>'Remove', :class=>'btn btn-xs btn-danger')
683
- end.to_s
688
+ end
684
689
  t << "</li>"
685
690
  end
686
691
  end
@@ -31,7 +31,11 @@ module AutoForme
31
31
  # Use Rails's form_authenticity_token for CSRF protection.
32
32
  def csrf_token_hash(action=nil)
33
33
  vc = @controller.view_context
34
- {vc.request_forgery_protection_token.to_s=>vc.form_authenticity_token} if vc.protect_against_forgery?
34
+ # :nocov:
35
+ if vc.protect_against_forgery?
36
+ # :nocov:
37
+ {vc.request_forgery_protection_token.to_s=>vc.form_authenticity_token}
38
+ end
35
39
  end
36
40
  end
37
41
 
@@ -58,7 +62,11 @@ module AutoForme
58
62
  elsif @autoforme_action.request.xhr?
59
63
  render :html=>@autoforme_text.html_safe
60
64
  else
61
- render :inline=>"<%=raw @autoforme_text %>", :layout=>true
65
+ opts = framework.opts[:view_options]
66
+ opts = opts ? opts.dup : {}
67
+ opts[:layout] = true unless opts.has_key?(:layout)
68
+ opts[:inline] = "<%=raw @autoforme_text %>"
69
+ render opts
62
70
  end
63
71
  else
64
72
  render :plain=>'Unhandled Request', :status=>404
@@ -40,29 +40,31 @@ module AutoForme
40
40
  # Set the flash at notice level when redirecting, so it shows
41
41
  # up on the redirected page.
42
42
  def set_flash_notice(message)
43
- @controller.flash[flash_symbol_keys? ? :notice : 'notice'] = message
43
+ @controller.flash[flash_key(:notice)] = message
44
44
  end
45
45
 
46
46
  # Set the current flash at error level, used when displaying
47
47
  # pages when there is an error.
48
48
  def set_flash_now_error(message)
49
- @controller.flash.now[flash_symbol_keys? ? :error : 'error'] = message
49
+ @controller.flash.now[flash_key(:error)] = message
50
50
  end
51
51
 
52
52
  # Use Rack::Csrf for csrf protection if it is defined.
53
53
  def csrf_token_hash(action=nil)
54
54
  if @controller.respond_to?(:check_csrf!)
55
55
  # Using route_csrf plugin
56
- # :nocov:
57
56
  token = if @controller.use_request_specific_csrf_tokens?
58
57
  @controller.csrf_token(@controller.csrf_path(action))
58
+ # :nocov:
59
59
  else
60
60
  @controller.csrf_token
61
+ # :nocov:
61
62
  end
62
63
  {@controller.csrf_field=>token}
63
64
  # :nocov:
64
- elsif defined?(::Rack::Csrf)
65
+ elsif defined?(::Rack::Csrf) && !@controller.opts[:no_csrf]
65
66
  {::Rack::Csrf.field=>::Rack::Csrf.token(@env)}
67
+ # :nocov:
66
68
  end
67
69
  end
68
70
 
@@ -71,6 +73,12 @@ module AutoForme
71
73
  def flash_symbol_keys?
72
74
  !@controller.opts[:sessions_convert_symbols]
73
75
  end
76
+
77
+ def flash_key(key)
78
+ # :nocov:
79
+ flash_symbol_keys? ? key : key.to_s
80
+ # :nocov:
81
+ end
74
82
  end
75
83
 
76
84
  attr_reader :route_proc
@@ -106,7 +114,10 @@ module AutoForme
106
114
  elsif @autoforme_action.request.xhr?
107
115
  @autoforme_text
108
116
  else
109
- view(:content=>@autoforme_text)
117
+ opts = framework.opts[:view_options]
118
+ opts = opts ? opts.dup : {}
119
+ opts[:content] = @autoforme_text
120
+ view(opts)
110
121
  end
111
122
  end
112
123
  end
@@ -30,7 +30,11 @@ module AutoForme
30
30
 
31
31
  # Use Rack::Csrf for csrf protection if it is defined.
32
32
  def csrf_token_hash(action=nil)
33
- {::Rack::Csrf.field=>::Rack::Csrf.token(@env)} if defined?(::Rack::Csrf)
33
+ # :nocov:
34
+ if defined?(::Rack::Csrf)
35
+ # :nocov:
36
+ {::Rack::Csrf.field=>::Rack::Csrf.token(@env)}
37
+ end
34
38
  end
35
39
  end
36
40
 
@@ -50,7 +54,8 @@ module AutoForme
50
54
  elsif @autoforme_action.request.xhr?
51
55
  @autoforme_text
52
56
  else
53
- erb "<%= @autoforme_text %>".dup
57
+ opts = framework.opts[:view_options]
58
+ erb("<%= @autoforme_text %>".dup, opts ? opts.dup : {})
54
59
  end
55
60
  else
56
61
  pass
@@ -58,10 +63,12 @@ module AutoForme
58
63
  end
59
64
 
60
65
  prefix = Regexp.escape(framework.prefix) if framework.prefix
66
+ # :nocov:
61
67
  if ::Sinatra::VERSION < '2'
62
68
  prefix = "\\A#{prefix}"
63
69
  suffix = "\\z"
64
70
  end
71
+ # :nocov:
65
72
  regexp = %r{#{prefix}/([\w:]+)/(\w+)(?:/([\w-]+))?#{suffix}}
66
73
  @controller.get regexp, &block
67
74
  @controller.post regexp, &block
@@ -389,7 +389,7 @@ module AutoForme
389
389
 
390
390
  def normalize_mtm_associations(assocs)
391
391
  if assocs == :all
392
- mtm_association_names
392
+ editable_mtm_association_names
393
393
  else
394
394
  Array(assocs)
395
395
  end