formular 0.2.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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.travis.yml +29 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +105 -0
- data/Rakefile +12 -0
- data/formular.gemspec +33 -0
- data/lib/formular.rb +8 -0
- data/lib/formular/attributes.rb +45 -0
- data/lib/formular/builder.rb +52 -0
- data/lib/formular/builders/basic.rb +64 -0
- data/lib/formular/builders/bootstrap3.rb +28 -0
- data/lib/formular/builders/bootstrap3_horizontal.rb +32 -0
- data/lib/formular/builders/bootstrap3_inline.rb +10 -0
- data/lib/formular/builders/bootstrap4.rb +36 -0
- data/lib/formular/builders/bootstrap4_horizontal.rb +39 -0
- data/lib/formular/builders/bootstrap4_inline.rb +15 -0
- data/lib/formular/builders/foundation6.rb +28 -0
- data/lib/formular/element.rb +135 -0
- data/lib/formular/element/bootstrap3.rb +70 -0
- data/lib/formular/element/bootstrap3/checkable_control.rb +105 -0
- data/lib/formular/element/bootstrap3/column_control.rb +45 -0
- data/lib/formular/element/bootstrap3/horizontal.rb +146 -0
- data/lib/formular/element/bootstrap3/input_group.rb +83 -0
- data/lib/formular/element/bootstrap4.rb +49 -0
- data/lib/formular/element/bootstrap4/checkable_control.rb +94 -0
- data/lib/formular/element/bootstrap4/custom_control.rb +120 -0
- data/lib/formular/element/bootstrap4/horizontal.rb +87 -0
- data/lib/formular/element/foundation6.rb +69 -0
- data/lib/formular/element/foundation6/checkable_control.rb +72 -0
- data/lib/formular/element/foundation6/input_group.rb +88 -0
- data/lib/formular/element/foundation6/wrapped_control.rb +21 -0
- data/lib/formular/element/module.rb +35 -0
- data/lib/formular/element/modules/checkable.rb +96 -0
- data/lib/formular/element/modules/collection.rb +17 -0
- data/lib/formular/element/modules/container.rb +60 -0
- data/lib/formular/element/modules/control.rb +42 -0
- data/lib/formular/element/modules/error.rb +48 -0
- data/lib/formular/element/modules/hint.rb +36 -0
- data/lib/formular/element/modules/label.rb +30 -0
- data/lib/formular/element/modules/wrapped_control.rb +73 -0
- data/lib/formular/elements.rb +295 -0
- data/lib/formular/helper.rb +53 -0
- data/lib/formular/html_block.rb +70 -0
- data/lib/formular/path.rb +30 -0
- data/lib/formular/version.rb +3 -0
- metadata +247 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'formular/element/module'
|
2
|
+
module Formular
|
3
|
+
class Element
|
4
|
+
module Modules
|
5
|
+
# This module adds the relevant option keys and defaults
|
6
|
+
# for elements that support collections
|
7
|
+
module Collection
|
8
|
+
include Formular::Element::Module
|
9
|
+
|
10
|
+
add_option_keys :collection, :label_method, :value_method
|
11
|
+
|
12
|
+
set_default :label_method, 'first'
|
13
|
+
set_default :value_method, 'last'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'formular/element/module'
|
2
|
+
module Formular
|
3
|
+
class Element
|
4
|
+
module Modules
|
5
|
+
# this module is used for element that contain something
|
6
|
+
# e.g. <label>Label Words</label>
|
7
|
+
# it is designed to accept content as a string (via the :content option)
|
8
|
+
# or as a block
|
9
|
+
# Alternatively you can produce blockless content by making use of the
|
10
|
+
# #start and #end methods e.g.
|
11
|
+
#
|
12
|
+
# element = Container.()
|
13
|
+
# element.start
|
14
|
+
# add your own content
|
15
|
+
# element.end
|
16
|
+
module Container
|
17
|
+
include Formular::Element::Module
|
18
|
+
|
19
|
+
add_option_keys :content
|
20
|
+
|
21
|
+
html do |element|
|
22
|
+
concat start_tag
|
23
|
+
concat element.content
|
24
|
+
concat end_tag
|
25
|
+
end
|
26
|
+
|
27
|
+
html(:start) { start_tag }
|
28
|
+
|
29
|
+
html(:end) { end_tag }
|
30
|
+
|
31
|
+
module InstanceMethods
|
32
|
+
def content
|
33
|
+
@block ? HtmlBlock.new(self, @block).call : options[:content].to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_content?
|
37
|
+
@block || options[:content]
|
38
|
+
end
|
39
|
+
|
40
|
+
def end
|
41
|
+
to_html(context: :end)
|
42
|
+
end
|
43
|
+
|
44
|
+
def start
|
45
|
+
to_html(context: :start)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Delegate missing methods to the builder
|
49
|
+
# TODO:: @apotonick is going to do something fancy here to delegate
|
50
|
+
# the builder methods rather then using this method missing.
|
51
|
+
def method_missing(method, *args, &block)
|
52
|
+
return super unless builder
|
53
|
+
|
54
|
+
builder.send(method, *args, &block)
|
55
|
+
end
|
56
|
+
end # module InstanceMethods
|
57
|
+
end # module Container
|
58
|
+
end # module Modules
|
59
|
+
end # class Element
|
60
|
+
end # module Formular
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'formular/element/module'
|
2
|
+
module Formular
|
3
|
+
class Element
|
4
|
+
module Modules
|
5
|
+
# include this module in an element to set the id,
|
6
|
+
# name & value based on the attribute name
|
7
|
+
module Control
|
8
|
+
include Formular::Element::Module
|
9
|
+
|
10
|
+
add_option_keys :attribute_name
|
11
|
+
|
12
|
+
set_default :name, :form_encoded_name
|
13
|
+
set_default :id, :form_encoded_id
|
14
|
+
set_default :value, :reader_value
|
15
|
+
|
16
|
+
module InstanceMethods
|
17
|
+
def attribute_name
|
18
|
+
options[:attribute_name]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def path
|
24
|
+
@path ||= builder.path(attribute_name) if attribute_name && builder
|
25
|
+
end
|
26
|
+
|
27
|
+
def form_encoded_name
|
28
|
+
path.to_encoded_name if path
|
29
|
+
end
|
30
|
+
|
31
|
+
def form_encoded_id
|
32
|
+
path.to_encoded_id if path
|
33
|
+
end
|
34
|
+
|
35
|
+
def reader_value
|
36
|
+
builder.reader_value(attribute_name) if attribute_name && builder
|
37
|
+
end
|
38
|
+
end # model InstanceMethods
|
39
|
+
end # module Control
|
40
|
+
end # module Modules
|
41
|
+
end # class Element
|
42
|
+
end # module Formular
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'formular/element/module'
|
2
|
+
module Formular
|
3
|
+
class Element
|
4
|
+
module Modules
|
5
|
+
# this module provides error methods and options to a control when included
|
6
|
+
module Error
|
7
|
+
include Formular::Element::Module
|
8
|
+
add_option_keys :error
|
9
|
+
|
10
|
+
# options functionality (same as SimpleForm):
|
11
|
+
# options[:error] == false NO ERROR regardless of model errors
|
12
|
+
# options[:error] == String return the string, regardless of model errors
|
13
|
+
module InstanceMethods
|
14
|
+
def error_text
|
15
|
+
has_custom_error? ? options[:error] : errors_on_attribute.send(error_method) if has_errors?
|
16
|
+
end
|
17
|
+
|
18
|
+
def has_errors?
|
19
|
+
options[:error] != false && (has_custom_error? || has_attribute_errors?)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
|
24
|
+
# attribute_errors is an array, what method should we use to return a
|
25
|
+
# string? (:first, :last, :join etc.)
|
26
|
+
# ideally this should be configurable via the builder...
|
27
|
+
def error_method
|
28
|
+
:first
|
29
|
+
end
|
30
|
+
|
31
|
+
# I bet we could clean this up alot but it needs to be flexible
|
32
|
+
# enough not to error with nils
|
33
|
+
def has_attribute_errors?
|
34
|
+
builder != nil && builder.errors != nil && errors_on_attribute != nil && errors_on_attribute.size > 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def has_custom_error?
|
38
|
+
options[:error].is_a?(String)
|
39
|
+
end
|
40
|
+
|
41
|
+
def errors_on_attribute
|
42
|
+
@errors ||= builder.errors[options[:attribute_name]]
|
43
|
+
end
|
44
|
+
end # module InstanceMethods
|
45
|
+
end # module Error
|
46
|
+
end # module Modules
|
47
|
+
end # class Element
|
48
|
+
end # module Formular
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'formular/element/module'
|
2
|
+
module Formular
|
3
|
+
class Element
|
4
|
+
module Modules
|
5
|
+
# this module provides hints to a control when included.
|
6
|
+
module Hint
|
7
|
+
include Formular::Element::Module
|
8
|
+
add_option_keys :hint, :hint_options
|
9
|
+
|
10
|
+
# options functionality (same as SimpleForm):
|
11
|
+
# options[:hint] == String return the string
|
12
|
+
module InstanceMethods
|
13
|
+
def hint_text
|
14
|
+
options[:hint] if has_hint?
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_hint?
|
18
|
+
options[:hint].is_a?(String)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def hint_id
|
23
|
+
return hint_options[:id] if hint_options[:id]
|
24
|
+
|
25
|
+
id = attributes[:id] || form_encoded_id
|
26
|
+
"#{id}_hint" if id
|
27
|
+
end
|
28
|
+
|
29
|
+
def hint_options
|
30
|
+
@hint_options ||= Attributes[options[:hint_options]]
|
31
|
+
end
|
32
|
+
end # module InstanceMethods
|
33
|
+
end # module Hint
|
34
|
+
end # module Modules
|
35
|
+
end # class Element
|
36
|
+
end # module Formular
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'formular/element/module'
|
2
|
+
module Formular
|
3
|
+
class Element
|
4
|
+
module Modules
|
5
|
+
# this module provides label options and methods to a control when included.
|
6
|
+
module Label
|
7
|
+
include Formular::Element::Module
|
8
|
+
add_option_keys :label, :label_options
|
9
|
+
|
10
|
+
# options functionality:
|
11
|
+
# options[:label] == String return the string
|
12
|
+
# currently we don't infer label text so if you don't include
|
13
|
+
# label as an option, you wont get one rendered
|
14
|
+
module InstanceMethods
|
15
|
+
def label_text
|
16
|
+
options[:label]
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_label?
|
20
|
+
!label_text.nil? && label_text != false
|
21
|
+
end
|
22
|
+
|
23
|
+
def label_options
|
24
|
+
@label_options ||= Attributes[options[:label_options]]
|
25
|
+
end
|
26
|
+
end # module InstanceMethods
|
27
|
+
end # module Label
|
28
|
+
end # module Modules
|
29
|
+
end # class Element
|
30
|
+
end # module Formular
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'formular/element/module'
|
2
|
+
require 'formular/element/modules/control'
|
3
|
+
require 'formular/element/modules/hint'
|
4
|
+
require 'formular/element/modules/error'
|
5
|
+
require 'formular/element/modules/label'
|
6
|
+
module Formular
|
7
|
+
class Element
|
8
|
+
module Modules
|
9
|
+
# include this module to enable an element to render the entire wrapped input
|
10
|
+
# e.g. wrapper{label+control+hint+error}
|
11
|
+
module WrappedControl
|
12
|
+
include Formular::Element::Module
|
13
|
+
include Control
|
14
|
+
include Hint
|
15
|
+
include Error
|
16
|
+
include Label
|
17
|
+
|
18
|
+
add_option_keys :error_options, :wrapper_options
|
19
|
+
set_default :aria_describedby, :hint_id, if: :has_hint?
|
20
|
+
|
21
|
+
self.html_context = :wrapped
|
22
|
+
|
23
|
+
html(:wrapped) do |input|
|
24
|
+
input.wrapper do
|
25
|
+
concat input.label
|
26
|
+
concat input.to_html(context: :default)
|
27
|
+
concat input.hint
|
28
|
+
concat input.error
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module InstanceMethods
|
33
|
+
def wrapper(&block)
|
34
|
+
wrapper_element = has_errors? ? :error_wrapper : :wrapper
|
35
|
+
builder.send(wrapper_element, Attributes[options[:wrapper_options]], &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def label
|
39
|
+
return '' unless has_label?
|
40
|
+
|
41
|
+
label_options[:content] = label_text
|
42
|
+
label_options[:labeled_control] = self
|
43
|
+
builder.label(label_options).to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def error
|
47
|
+
return '' unless has_errors?
|
48
|
+
|
49
|
+
error_options[:content] = error_text
|
50
|
+
builder.error(error_options).to_s
|
51
|
+
end
|
52
|
+
|
53
|
+
def hint
|
54
|
+
return '' unless has_hint?
|
55
|
+
|
56
|
+
hint_options[:content] = hint_text
|
57
|
+
hint_options[:id] ||= hint_id
|
58
|
+
builder.hint(hint_options).to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def error_options
|
63
|
+
@error_options ||= Attributes[options[:error_options]]
|
64
|
+
end
|
65
|
+
|
66
|
+
def wrapper_options
|
67
|
+
@wrapper_options ||= Attributes[options[:wrapper_options]]
|
68
|
+
end
|
69
|
+
end # module InstanceMethods
|
70
|
+
end # module WrappedControl
|
71
|
+
end # module Modules
|
72
|
+
end # class Element
|
73
|
+
end # module Formular
|
@@ -0,0 +1,295 @@
|
|
1
|
+
require 'formular/element'
|
2
|
+
require 'formular/element/module'
|
3
|
+
require 'formular/element/modules/container'
|
4
|
+
require 'formular/element/modules/wrapped_control'
|
5
|
+
require 'formular/element/modules/control'
|
6
|
+
require 'formular/element/modules/checkable'
|
7
|
+
require 'formular/element/modules/error'
|
8
|
+
|
9
|
+
module Formular
|
10
|
+
class Element
|
11
|
+
# These three are really just provided for convenience when creating other elements
|
12
|
+
Container = Class.new(Formular::Element) { include Formular::Element::Modules::Container }
|
13
|
+
Control = Class.new(Formular::Element) { include Formular::Element::Modules::Control }
|
14
|
+
WrappedControl = Class.new(Formular::Element) { include Formular::Element::Modules::WrappedControl }
|
15
|
+
|
16
|
+
# define some base classes to build from or easily use elsewhere
|
17
|
+
Option = Class.new(Container) { tag :option }
|
18
|
+
OptGroup = Class.new(Container) { tag :optgroup }
|
19
|
+
Fieldset = Class.new(Container) { tag :fieldset }
|
20
|
+
Legend = Class.new(Container) { tag :legend }
|
21
|
+
Div = Class.new(Container) { tag :div }
|
22
|
+
P = Class.new(Container) { tag :p }
|
23
|
+
Span = Class.new(Container) { tag :span }
|
24
|
+
Small = Class.new(Container) { tag :small }
|
25
|
+
|
26
|
+
class Hidden < Control
|
27
|
+
tag :input
|
28
|
+
set_default :type, 'hidden'
|
29
|
+
|
30
|
+
html { closed_start_tag }
|
31
|
+
end
|
32
|
+
|
33
|
+
class Form < Container
|
34
|
+
tag :form
|
35
|
+
|
36
|
+
add_option_keys :enforce_utf8, :csrf_token, :csrf_token_name
|
37
|
+
|
38
|
+
set_default :method, 'post'
|
39
|
+
set_default :accept_charset, 'utf-8'
|
40
|
+
set_default :enforce_utf8, true
|
41
|
+
|
42
|
+
html(:start) do |form|
|
43
|
+
hidden_tags = element.extra_hidden_tags
|
44
|
+
concat start_tag
|
45
|
+
concat hidden_tags
|
46
|
+
end
|
47
|
+
|
48
|
+
html do |form|
|
49
|
+
concat form.to_html(context: :start)
|
50
|
+
concat form.content
|
51
|
+
concat end_tag
|
52
|
+
end
|
53
|
+
|
54
|
+
def extra_hidden_tags
|
55
|
+
token_tag + utf8_enforcer_tag + method_tag
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def token_tag
|
61
|
+
return '' unless options[:csrf_token].is_a? String
|
62
|
+
|
63
|
+
name = options[:csrf_token_name] || '_csrf_token'
|
64
|
+
|
65
|
+
Hidden.(value: options[:csrf_token], name: name).to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
def utf8_enforcer_tag
|
69
|
+
return '' unless options[:enforce_utf8]
|
70
|
+
|
71
|
+
# Use raw HTML to ensure the value is written as an HTML entity; it
|
72
|
+
# needs to be the right character regardless of which encoding the
|
73
|
+
# browser infers.
|
74
|
+
%(<input name="utf8" type="hidden" value="✓"/>)
|
75
|
+
end
|
76
|
+
|
77
|
+
# because this mutates attributes, we have to call this before rendering the start_tag
|
78
|
+
def method_tag
|
79
|
+
method = attributes[:method]
|
80
|
+
|
81
|
+
case method
|
82
|
+
when /^get$/ # must be case-insensitive, but can't use downcase as might be nil
|
83
|
+
attributes[:method] = 'get'
|
84
|
+
''
|
85
|
+
when /^post$/, '', nil
|
86
|
+
attributes[:method] = 'post'
|
87
|
+
''
|
88
|
+
else
|
89
|
+
attributes[:method] = 'post'
|
90
|
+
Hidden.(value: method, name: '_method').to_s
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class ErrorNotification < Formular::Element
|
96
|
+
tag :div
|
97
|
+
add_option_keys :message
|
98
|
+
|
99
|
+
html do |element|
|
100
|
+
if element.builder_errors?
|
101
|
+
concat start_tag
|
102
|
+
concat element.error_message
|
103
|
+
concat end_tag
|
104
|
+
else
|
105
|
+
''
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def error_message
|
110
|
+
options[:message] || 'Please review the problems below:'
|
111
|
+
end
|
112
|
+
|
113
|
+
def builder_errors?
|
114
|
+
return false if builder.nil?
|
115
|
+
!builder.errors.empty?
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class Error < P
|
120
|
+
include Formular::Element::Modules::Error
|
121
|
+
add_option_keys :attribute_name
|
122
|
+
set_default :content, :error_text
|
123
|
+
end # class Error
|
124
|
+
|
125
|
+
class Textarea < Control
|
126
|
+
include Formular::Element::Modules::Container
|
127
|
+
tag :textarea
|
128
|
+
add_option_keys :value
|
129
|
+
|
130
|
+
def content
|
131
|
+
options[:value] || super
|
132
|
+
end
|
133
|
+
end # class Textarea
|
134
|
+
|
135
|
+
class Label < Container
|
136
|
+
tag :label
|
137
|
+
add_option_keys :labeled_control, :attribute_name
|
138
|
+
set_default :for, :labeled_control_id
|
139
|
+
|
140
|
+
# as per MDN A label element can have both a 'for' attribute and a contained control element,
|
141
|
+
# as long as the for attribute points to the contained control element.
|
142
|
+
def labeled_control_id
|
143
|
+
return options[:labeled_control].attributes[:id] if options[:labeled_control]
|
144
|
+
return builder.path(options[:attribute_name]).to_encoded_id if options[:attribute_name] && builder
|
145
|
+
end
|
146
|
+
end # class Label
|
147
|
+
|
148
|
+
class Submit < Formular::Element
|
149
|
+
tag :input
|
150
|
+
|
151
|
+
set_default :type, 'submit'
|
152
|
+
|
153
|
+
html { closed_start_tag }
|
154
|
+
end # class Submit
|
155
|
+
|
156
|
+
class Button < Formular::Element::Container
|
157
|
+
tag :button
|
158
|
+
add_option_keys :value
|
159
|
+
|
160
|
+
def content
|
161
|
+
options[:value] || super
|
162
|
+
end
|
163
|
+
end # class Button
|
164
|
+
|
165
|
+
class Input < Control
|
166
|
+
tag :input
|
167
|
+
set_default :type, 'text'
|
168
|
+
html { closed_start_tag }
|
169
|
+
end # class Input
|
170
|
+
|
171
|
+
class Select < Control
|
172
|
+
include Formular::Element::Modules::Collection
|
173
|
+
tag :select
|
174
|
+
|
175
|
+
add_option_keys :value
|
176
|
+
|
177
|
+
html do |input|
|
178
|
+
concat start_tag
|
179
|
+
concat input.option_tags
|
180
|
+
concat end_tag
|
181
|
+
end
|
182
|
+
|
183
|
+
# convert the collection array into option tags also supports option groups
|
184
|
+
# when the array is nested
|
185
|
+
# example 1:
|
186
|
+
# [[1,"True"], [0,"False"]] =>
|
187
|
+
# <option value="1">true</option><option value="0">false</option>
|
188
|
+
# example 2:
|
189
|
+
# [
|
190
|
+
# ["Genders", [["m", "Male"], ["f", "Female"]]],
|
191
|
+
# ["Booleans", [[1,"true"], [0,"false"]]]
|
192
|
+
# ] =>
|
193
|
+
# <optgroup label="Genders">
|
194
|
+
# <option value="m">Male</option>
|
195
|
+
# <option value="f">Female</option>
|
196
|
+
# </optgroup>
|
197
|
+
# <optgroup label="Booleans">
|
198
|
+
# <option value="1">true</option>
|
199
|
+
# <option value="0">false</option>
|
200
|
+
# </optgroup>
|
201
|
+
def option_tags
|
202
|
+
collection_to_options(options[:collection])
|
203
|
+
end
|
204
|
+
|
205
|
+
private
|
206
|
+
|
207
|
+
def collection_to_options(collection)
|
208
|
+
collection.map do |item|
|
209
|
+
if item.last.is_a?(Array)
|
210
|
+
opts = { label: item.first, content: collection_to_options(item.last) }
|
211
|
+
|
212
|
+
Formular::Element::OptGroup.new(opts).to_s
|
213
|
+
else
|
214
|
+
item_to_option(item)
|
215
|
+
end
|
216
|
+
end.join ''
|
217
|
+
end
|
218
|
+
|
219
|
+
def item_to_option(item)
|
220
|
+
opts = if item.is_a?(Array) && item.size > 2
|
221
|
+
item.pop
|
222
|
+
else
|
223
|
+
{}
|
224
|
+
end
|
225
|
+
|
226
|
+
opts[:value] = item.send(options[:value_method])
|
227
|
+
opts[:content] = item.send(options[:label_method])
|
228
|
+
opts[:selected] = 'selected' if opts[:value] == options[:value]
|
229
|
+
|
230
|
+
Formular::Element::Option.new(opts).to_s
|
231
|
+
end
|
232
|
+
end # class Select
|
233
|
+
|
234
|
+
class Checkbox < Control
|
235
|
+
tag :input
|
236
|
+
|
237
|
+
add_option_keys :unchecked_value, :include_hidden, :multiple
|
238
|
+
|
239
|
+
set_default :type, 'checkbox'
|
240
|
+
set_default :unchecked_value, :default_unchecked_value
|
241
|
+
set_default :value, '1' # instead of reader value
|
242
|
+
set_default :include_hidden, true
|
243
|
+
|
244
|
+
include Formular::Element::Modules::Checkable
|
245
|
+
|
246
|
+
html do |element|
|
247
|
+
if element.collection?
|
248
|
+
element.to_html(context: :with_collection)
|
249
|
+
else
|
250
|
+
concat element.hidden_tag
|
251
|
+
concat closed_start_tag
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
html(:with_collection) do |element|
|
256
|
+
concat element.to_html(context: :collection)
|
257
|
+
concat element.hidden_tag
|
258
|
+
end
|
259
|
+
|
260
|
+
def hidden_tag
|
261
|
+
return '' unless options[:include_hidden]
|
262
|
+
|
263
|
+
Hidden.(value: options[:unchecked_value], name: attributes[:name]).to_s
|
264
|
+
end
|
265
|
+
|
266
|
+
private
|
267
|
+
|
268
|
+
def default_unchecked_value
|
269
|
+
collection? ? '' : '0'
|
270
|
+
end
|
271
|
+
|
272
|
+
# only append the [] to name if part of a collection, or the multiple option is set
|
273
|
+
def form_encoded_name
|
274
|
+
return unless path
|
275
|
+
|
276
|
+
options[:multiple] || options[:collection] ? super + '[]' : super
|
277
|
+
end
|
278
|
+
|
279
|
+
def collection_base_options
|
280
|
+
super.merge(include_hidden: false)
|
281
|
+
end
|
282
|
+
end # class Checkbox
|
283
|
+
|
284
|
+
class Radio < Control
|
285
|
+
tag :input
|
286
|
+
|
287
|
+
set_default :type, 'radio'
|
288
|
+
set_default :value, nil # instead of reader value
|
289
|
+
|
290
|
+
include Formular::Element::Modules::Checkable
|
291
|
+
|
292
|
+
html { closed_start_tag }
|
293
|
+
end # class Radio
|
294
|
+
end # class Element
|
295
|
+
end # module Formular
|