foundation_rails_helper 2.0.0 → 3.0.0.beta3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -6
- data/.rubocop_todo.yml +6 -48
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -0
- data/README.md +23 -26
- data/Rakefile +1 -0
- data/foundation_rails_helper.gemspec +36 -32
- data/lib/foundation_rails_helper.rb +2 -0
- data/lib/foundation_rails_helper/action_view_extension.rb +1 -0
- data/lib/foundation_rails_helper/configuration.rb +4 -1
- data/lib/foundation_rails_helper/flash_helper.rb +43 -16
- data/lib/foundation_rails_helper/form_builder.rb +61 -83
- data/lib/foundation_rails_helper/size_class_calculator.rb +32 -0
- data/lib/foundation_rails_helper/version.rb +2 -1
- data/lib/railtie.rb +1 -0
- data/spec/.rubocop.yml +3 -0
- data/spec/foundation_rails_helper/configuration_spec.rb +30 -3
- data/spec/foundation_rails_helper/flash_helper_spec.rb +37 -23
- data/spec/foundation_rails_helper/form_builder_spec.rb +448 -176
- data/spec/spec_helper.rb +1 -0
- data/spec/support/classes/author.rb +13 -0
- data/spec/support/classes/book.rb +13 -0
- data/spec/support/classes/genre.rb +13 -0
- data/spec/support/mock_rails.rb +56 -100
- metadata +50 -20
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require 'action_view/helpers'
|
2
3
|
|
3
4
|
module FoundationRailsHelper
|
4
5
|
class FormBuilder < ActionView::Helpers::FormBuilder
|
5
6
|
include ActionView::Helpers::TagHelper
|
7
|
+
include ActionView::Helpers::OutputSafetyHelper
|
6
8
|
%w(file_field email_field text_field text_area telephone_field phone_field
|
7
9
|
url_field number_field date_field datetime_field datetime_local_field
|
8
10
|
month_field week_field time_field range_field search_field color_field)
|
@@ -17,21 +19,23 @@ module FoundationRailsHelper
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def label(attribute, text = nil, options = {})
|
20
|
-
if
|
22
|
+
if error?(attribute)
|
21
23
|
options[:class] ||= ''
|
22
|
-
options[:class] += '
|
24
|
+
options[:class] += ' is-invalid-label'
|
23
25
|
end
|
24
26
|
|
25
27
|
super(attribute, (text || '').html_safe, options)
|
26
28
|
end
|
27
29
|
|
30
|
+
# rubocop:disable LineLength
|
28
31
|
def check_box(attribute, options = {}, checked_value = '1', unchecked_value = '0')
|
29
32
|
custom_label(attribute, options[:label], options[:label_options]) do
|
30
33
|
options.delete(:label)
|
31
34
|
options.delete(:label_options)
|
32
35
|
super(attribute, options, checked_value, unchecked_value)
|
33
|
-
end +
|
36
|
+
end + error_and_help_text(attribute, options)
|
34
37
|
end
|
38
|
+
# rubocop:enable LineLength
|
35
39
|
|
36
40
|
def radio_button(attribute, tag_value, options = {})
|
37
41
|
options[:label_options] ||= {}
|
@@ -62,12 +66,14 @@ module FoundationRailsHelper
|
|
62
66
|
end
|
63
67
|
end
|
64
68
|
|
69
|
+
# rubocop:disable LineLength
|
65
70
|
def time_zone_select(attribute, priorities = nil, options = {}, html_options = {})
|
66
71
|
field attribute, options, html_options do |html_opts|
|
67
72
|
super(attribute, priorities, options,
|
68
73
|
html_opts.merge(autocomplete: :off))
|
69
74
|
end
|
70
75
|
end
|
76
|
+
# rubocop:enable LineLength
|
71
77
|
|
72
78
|
def select(attribute, choices, options = {}, html_options = {})
|
73
79
|
field attribute, options, html_options do |html_opts|
|
@@ -76,6 +82,7 @@ module FoundationRailsHelper
|
|
76
82
|
end
|
77
83
|
end
|
78
84
|
|
85
|
+
# rubocop:disable LineLength, ParameterLists
|
79
86
|
def collection_select(attribute, collection, value_method, text_method, options = {}, html_options = {})
|
80
87
|
field attribute, options, html_options do |html_opts|
|
81
88
|
html_options[:autocomplete] ||= :off
|
@@ -91,6 +98,7 @@ module FoundationRailsHelper
|
|
91
98
|
option_key_method, option_value_method, options, html_opts)
|
92
99
|
end
|
93
100
|
end
|
101
|
+
# rubocop:enable LineLength, ParameterLists
|
94
102
|
|
95
103
|
def autocomplete(attribute, url, options = {})
|
96
104
|
field attribute, options do |opts|
|
@@ -105,71 +113,43 @@ module FoundationRailsHelper
|
|
105
113
|
super(value, options)
|
106
114
|
end
|
107
115
|
|
108
|
-
private
|
109
|
-
|
110
|
-
def has_error?(attribute)
|
111
|
-
object.respond_to?(:errors) && !object.errors[attribute].blank?
|
112
|
-
end
|
113
|
-
|
114
116
|
def error_for(attribute, options = {})
|
115
|
-
|
116
|
-
class_name += " #{options[:class]}" if options[:class]
|
117
|
+
return unless error?(attribute)
|
117
118
|
|
118
|
-
|
119
|
+
class_name = 'form-error is-visible'
|
120
|
+
class_name += " #{options[:class]}" if options[:class]
|
119
121
|
|
120
122
|
error_messages = object.errors[attribute].join(', ')
|
121
123
|
error_messages = error_messages.html_safe if options[:html_safe_errors]
|
122
|
-
content_tag(:small, error_messages,
|
124
|
+
content_tag(:small, error_messages,
|
125
|
+
class: class_name.sub('is-invalid-input', ''))
|
123
126
|
end
|
124
127
|
|
125
|
-
|
126
|
-
return block_given? ? yield.html_safe : ''.html_safe if text == false
|
127
|
-
if text.nil? || text == true
|
128
|
-
text =
|
129
|
-
if object.class.respond_to?(:human_attribute_name)
|
130
|
-
object.class.human_attribute_name(attribute)
|
131
|
-
else
|
132
|
-
attribute.to_s.humanize
|
133
|
-
end
|
134
|
-
end
|
135
|
-
text = yield.html_safe + " #{text}" if block_given?
|
136
|
-
options ||= {}
|
137
|
-
label(attribute, text, options)
|
138
|
-
end
|
128
|
+
private
|
139
129
|
|
140
|
-
def
|
141
|
-
|
142
|
-
classes + ' columns'
|
130
|
+
def error?(attribute)
|
131
|
+
object.respond_to?(:errors) && !object.errors[attribute].blank?
|
143
132
|
end
|
144
133
|
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
@medium = size_options[:medium]
|
149
|
-
@large = size_options[:large]
|
134
|
+
def default_label_text(object, attribute)
|
135
|
+
if object.class.respond_to?(:human_attribute_name)
|
136
|
+
return object.class.human_attribute_name(attribute)
|
150
137
|
end
|
151
138
|
|
152
|
-
|
153
|
-
|
154
|
-
end
|
155
|
-
|
156
|
-
private
|
157
|
-
|
158
|
-
def small_class
|
159
|
-
"small-#{@small}" if valid_size(@small)
|
160
|
-
end
|
139
|
+
attribute.to_s.humanize
|
140
|
+
end
|
161
141
|
|
162
|
-
|
163
|
-
|
164
|
-
end
|
142
|
+
def custom_label(attribute, text, options)
|
143
|
+
return block_given? ? yield.html_safe : ''.html_safe if text == false
|
165
144
|
|
166
|
-
|
167
|
-
|
168
|
-
|
145
|
+
text = default_label_text(object, attribute) if text.nil? || text == true
|
146
|
+
text = safe_join([yield, text.html_safe]) if block_given?
|
147
|
+
label(attribute, text, options || {})
|
148
|
+
end
|
169
149
|
|
170
|
-
|
171
|
-
|
172
|
-
|
150
|
+
def column_classes(options)
|
151
|
+
classes = SizeClassCalculator.new(options).classes
|
152
|
+
classes + ' columns'
|
173
153
|
end
|
174
154
|
|
175
155
|
def tag_from_options(name, options)
|
@@ -181,7 +161,7 @@ module FoundationRailsHelper
|
|
181
161
|
end
|
182
162
|
|
183
163
|
def decrement_input_size(input, column, options)
|
184
|
-
return unless options.key?(column)
|
164
|
+
return unless options.present? && options.key?(column)
|
185
165
|
|
186
166
|
input.send("#{column}=",
|
187
167
|
(input.send(column) - options.fetch(column).to_i))
|
@@ -191,15 +171,9 @@ module FoundationRailsHelper
|
|
191
171
|
def calculate_input_size(prefix_options, postfix_options)
|
192
172
|
input_size =
|
193
173
|
OpenStruct.new(changed?: false, small: 12, medium: 12, large: 12)
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
end
|
198
|
-
end
|
199
|
-
if postfix_options.present?
|
200
|
-
%w(small medium large).each do |size|
|
201
|
-
decrement_input_size(input_size, size.to_sym, postfix_options)
|
202
|
-
end
|
174
|
+
%w(small medium large).each do |size|
|
175
|
+
decrement_input_size(input_size, size.to_sym, prefix_options)
|
176
|
+
decrement_input_size(input_size, size.to_sym, postfix_options)
|
203
177
|
end
|
204
178
|
|
205
179
|
input_size
|
@@ -213,45 +187,49 @@ module FoundationRailsHelper
|
|
213
187
|
klass = column_classes(input_size.marshal_dump).to_s
|
214
188
|
input = content_tag(:div, block, class: klass)
|
215
189
|
|
216
|
-
|
217
|
-
|
218
|
-
content_tag(:div, prefix + input + postfix, class: 'row collapse')
|
219
|
-
else
|
220
|
-
block
|
221
|
-
end
|
222
|
-
|
223
|
-
html.html_safe
|
190
|
+
return block unless input_size.changed?
|
191
|
+
content_tag(:div, prefix + input + postfix, class: 'row collapse')
|
224
192
|
end
|
225
193
|
|
226
|
-
def
|
194
|
+
def error_and_help_text(attribute, options = {})
|
227
195
|
html = ''
|
228
|
-
|
196
|
+
if options[:help_text]
|
197
|
+
html += content_tag(:p, options[:help_text], class: 'help-text')
|
198
|
+
end
|
229
199
|
html += error_for(attribute, options) || ''
|
230
200
|
html.html_safe
|
231
201
|
end
|
232
202
|
|
203
|
+
def field_label(attribute, options)
|
204
|
+
return ''.html_safe unless auto_labels || options[:label]
|
205
|
+
custom_label(attribute, options[:label], options[:label_options])
|
206
|
+
end
|
207
|
+
|
233
208
|
def field(attribute, options, html_options = nil)
|
234
|
-
|
235
|
-
html = if auto_labels || options[:label]
|
236
|
-
custom_label(attribute, options[:label], options[:label_options])
|
237
|
-
else
|
238
|
-
''.html_safe
|
239
|
-
end
|
209
|
+
html = field_label(attribute, options)
|
240
210
|
class_options = html_options || options
|
241
211
|
|
242
|
-
if
|
212
|
+
if error?(attribute)
|
243
213
|
class_options[:class] = class_options[:class].to_s
|
244
|
-
class_options[:class] += '
|
214
|
+
class_options[:class] += ' is-invalid-input'
|
245
215
|
end
|
246
216
|
|
247
217
|
options.delete(:label)
|
248
218
|
options.delete(:label_options)
|
249
|
-
|
219
|
+
help_text = options.delete(:help_text)
|
250
220
|
prefix = options.delete(:prefix)
|
251
221
|
postfix = options.delete(:postfix)
|
252
222
|
|
253
223
|
html += wrap_prefix_and_postfix(yield(class_options), prefix, postfix)
|
254
|
-
html +
|
224
|
+
html + error_and_help_text(attribute, options.merge(help_text: help_text))
|
225
|
+
end
|
226
|
+
|
227
|
+
def auto_labels
|
228
|
+
if @options[:auto_labels].nil?
|
229
|
+
FoundationRailsHelper.configuration.auto_labels
|
230
|
+
else
|
231
|
+
@options[:auto_labels]
|
232
|
+
end
|
255
233
|
end
|
256
234
|
end
|
257
235
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module FoundationRailsHelper
|
3
|
+
class SizeClassCalculator
|
4
|
+
def initialize(size_options)
|
5
|
+
@small = size_options[:small]
|
6
|
+
@medium = size_options[:medium]
|
7
|
+
@large = size_options[:large]
|
8
|
+
end
|
9
|
+
|
10
|
+
def classes
|
11
|
+
[small_class, medium_class, large_class].compact.join(' ')
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def small_class
|
17
|
+
"small-#{@small}" if valid_size(@small)
|
18
|
+
end
|
19
|
+
|
20
|
+
def medium_class
|
21
|
+
"medium-#{@medium}" if valid_size(@medium)
|
22
|
+
end
|
23
|
+
|
24
|
+
def large_class
|
25
|
+
"large-#{@large}" if valid_size(@large)
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid_size(value)
|
29
|
+
value.present? && value.to_i < 12
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/railtie.rb
CHANGED
data/spec/.rubocop.yml
CHANGED
@@ -1,11 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require "spec_helper"
|
2
3
|
|
3
4
|
describe FoundationRailsHelper do
|
4
5
|
describe FoundationRailsHelper::Configuration do
|
5
6
|
describe "#button_class" do
|
6
|
-
it "default value is '
|
7
|
+
it "default value is 'success button'" do
|
7
8
|
config = FoundationRailsHelper::Configuration.new
|
8
|
-
expect(config.button_class).to eq("
|
9
|
+
expect(config.button_class).to eq("success button")
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
@@ -32,6 +33,21 @@ describe FoundationRailsHelper do
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
36
|
+
describe "#auto_labels" do
|
37
|
+
it "default value is 'true'" do
|
38
|
+
config = FoundationRailsHelper::Configuration.new
|
39
|
+
expect(config.auto_labels).to be(true)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#auto_labels=" do
|
44
|
+
it "can set the value" do
|
45
|
+
config = FoundationRailsHelper::Configuration.new
|
46
|
+
config.auto_labels = false
|
47
|
+
expect(config.auto_labels).to be(false)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
35
51
|
describe ".reset" do
|
36
52
|
it "resets the configured button class" do
|
37
53
|
FoundationRailsHelper.configure do |config|
|
@@ -41,7 +57,7 @@ describe FoundationRailsHelper do
|
|
41
57
|
FoundationRailsHelper.reset
|
42
58
|
|
43
59
|
config = FoundationRailsHelper.configuration
|
44
|
-
expect(config.button_class).to eq("
|
60
|
+
expect(config.button_class).to eq("success button")
|
45
61
|
end
|
46
62
|
|
47
63
|
it "resets the configured ignored flash keys" do
|
@@ -54,6 +70,17 @@ describe FoundationRailsHelper do
|
|
54
70
|
config = FoundationRailsHelper.configuration
|
55
71
|
expect(config.ignored_flash_keys).to eq([])
|
56
72
|
end
|
73
|
+
|
74
|
+
it "resets the configured auto labels" do
|
75
|
+
FoundationRailsHelper.configure do |config|
|
76
|
+
config.auto_labels = false
|
77
|
+
end
|
78
|
+
|
79
|
+
FoundationRailsHelper.reset
|
80
|
+
|
81
|
+
config = FoundationRailsHelper.configuration
|
82
|
+
expect(config.auto_labels).to be(true)
|
83
|
+
end
|
57
84
|
end
|
58
85
|
end
|
59
86
|
end
|
@@ -1,60 +1,64 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
3
2
|
require "spec_helper"
|
4
3
|
|
5
4
|
describe FoundationRailsHelper::FlashHelper do
|
6
5
|
include ActionView::Context if defined?(ActionView::Context)
|
7
|
-
include ActionView::Helpers::
|
8
|
-
include ActionView::Helpers::TagHelper
|
9
|
-
include ActionView::Helpers::TextHelper
|
6
|
+
include ActionView::Helpers::FormTagHelper
|
10
7
|
include FoundationRailsHelper::FlashHelper
|
11
8
|
|
12
|
-
FoundationRailsHelper::FlashHelper::DEFAULT_KEY_MATCHING.
|
13
|
-
|
14
|
-
|
9
|
+
KEY_MATCHING = FoundationRailsHelper::FlashHelper::DEFAULT_KEY_MATCHING.freeze
|
10
|
+
|
11
|
+
KEY_MATCHING.each do |type, klass|
|
12
|
+
it "displays flash message with #{klass} class for #{type} message" do
|
13
|
+
allow(self).to receive(:flash).and_return(type.to_s => "Flash message")
|
15
14
|
node = Capybara.string display_flash_messages
|
16
15
|
expect(node)
|
17
|
-
.to have_css("div.
|
18
|
-
.and have_css("
|
16
|
+
.to have_css("div.flash.callout.#{klass}", text: "Flash message")
|
17
|
+
.and have_css("[data-close]", text: "×")
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
21
|
it "handles symbol keys" do
|
23
22
|
allow(self).to receive(:flash).and_return(success: "Flash message")
|
24
23
|
node = Capybara.string display_flash_messages
|
25
|
-
expect(node).to have_css("div.
|
24
|
+
expect(node).to have_css("div.callout.success", text: "Flash message")
|
26
25
|
end
|
27
26
|
|
28
27
|
it "handles string keys" do
|
29
28
|
allow(self).to receive(:flash).and_return("success" => "Flash message")
|
30
29
|
node = Capybara.string display_flash_messages
|
31
|
-
expect(node).to have_css("div.
|
30
|
+
expect(node).to have_css("div.callout.success", text: "Flash message")
|
32
31
|
end
|
33
32
|
|
34
33
|
it "displays multiple flash messages" do
|
35
|
-
allow(self).to receive(:flash)
|
34
|
+
allow(self).to receive(:flash)
|
35
|
+
.and_return("success" => "Yay it worked",
|
36
|
+
"error" => "But this other thing failed")
|
36
37
|
node = Capybara.string display_flash_messages
|
37
38
|
expect(node)
|
38
|
-
.to have_css("div.
|
39
|
-
.and have_css("div.
|
39
|
+
.to have_css("div.callout.success", text: "Yay it worked")
|
40
|
+
.and have_css("div.callout.alert", text: "But this other thing failed")
|
40
41
|
end
|
41
42
|
|
42
43
|
it "displays flash message with overridden key matching" do
|
43
44
|
allow(self).to receive(:flash).and_return("notice" => "Flash message")
|
44
|
-
node =
|
45
|
-
|
45
|
+
node =
|
46
|
+
Capybara.string display_flash_messages(key_matching: { notice: :alert })
|
47
|
+
expect(node).to have_css("div.callout.alert", text: "Flash message")
|
46
48
|
end
|
47
49
|
|
48
50
|
it "displays flash message with custom key matching" do
|
49
51
|
allow(self).to receive(:flash).and_return("custom_type" => "Flash message")
|
50
|
-
node = Capybara.string
|
51
|
-
|
52
|
+
node = Capybara.string(
|
53
|
+
display_flash_messages(key_matching: { custom_type: :custom_class })
|
54
|
+
)
|
55
|
+
expect(node).to have_css("div.callout.custom_class", text: "Flash message")
|
52
56
|
end
|
53
57
|
|
54
58
|
it "displays flash message with standard class if key doesn't match" do
|
55
59
|
allow(self).to receive(:flash).and_return("custom_type" => "Flash message")
|
56
60
|
node = Capybara.string display_flash_messages
|
57
|
-
expect(node).to have_css("div.
|
61
|
+
expect(node).to have_css("div.callout.primary", text: "Flash message")
|
58
62
|
end
|
59
63
|
|
60
64
|
context "when the flash hash contains devise internal data" do
|
@@ -73,13 +77,23 @@ describe FoundationRailsHelper::FlashHelper do
|
|
73
77
|
allow(self).to receive(:flash).and_return("timedout" => true)
|
74
78
|
expect(display_flash_messages).to be_nil
|
75
79
|
|
76
|
-
# Ideally we'd create a node using Capybara.string, as in the other
|
77
|
-
# and set the following expectation:
|
78
|
-
# expect(node).to_not have_css("div.
|
80
|
+
# Ideally we'd create a node using Capybara.string, as in the other
|
81
|
+
# examples and set the following expectation:
|
82
|
+
# expect(node).to_not have_css("div.callout")
|
79
83
|
# but Capybara.string doesn't behave nicely with nil input:
|
80
84
|
# the input gets assigned to the @native instance variable,
|
81
85
|
# which is used by the css matcher, so we get the following error:
|
82
86
|
# undefined method `css' for nil:NilClass
|
83
87
|
end
|
84
88
|
end
|
89
|
+
|
90
|
+
context "with (closable: false) option" do
|
91
|
+
it "doesn't display the close button" do
|
92
|
+
allow(self).to receive(:flash).and_return(success: "Flash message")
|
93
|
+
node = Capybara.string display_flash_messages(closable: false)
|
94
|
+
expect(node)
|
95
|
+
.to have_css("div.flash.callout.success", text: "Flash message")
|
96
|
+
.and have_no_css("[data-close]", text: "×")
|
97
|
+
end
|
98
|
+
end
|
85
99
|
end
|