lotus-helpers 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,790 @@
1
+ require 'lotus/helpers/form_helper/html_node'
2
+ require 'lotus/helpers/form_helper/values'
3
+ require 'lotus/helpers/html_helper/html_builder'
4
+ require 'lotus/utils/string'
5
+
6
+ module Lotus
7
+ module Helpers
8
+ module FormHelper
9
+ # Form builder
10
+ #
11
+ # @since x.x.x
12
+ #
13
+ # @see Lotus::Helpers::HtmlHelper::HtmlBuilder
14
+ class FormBuilder < ::Lotus::Helpers::HtmlHelper::HtmlBuilder
15
+ # Set of HTTP methods that are understood by web browsers
16
+ #
17
+ # @since x.x.x
18
+ # @api private
19
+ BROWSER_METHODS = ['GET', 'POST'].freeze
20
+
21
+ # Checked attribute value
22
+ #
23
+ # @since x.x.x
24
+ # @api private
25
+ #
26
+ # @see Lotus::Helpers::FormHelper::FormBuilder#radio_button
27
+ CHECKED = 'checked'.freeze
28
+
29
+ # Selected attribute value for option
30
+ #
31
+ # @since x.x.x
32
+ # @api private
33
+ #
34
+ # @see Lotus::Helpers::FormHelper::FormBuilder#select
35
+ SELECTED = 'selected'.freeze
36
+
37
+ # Separator for accept attribute of file input
38
+ #
39
+ # @since x.x.x
40
+ # @api private
41
+ #
42
+ # @see Lotus::Helpers::FormHelper::FormBuilder#file_input
43
+ ACCEPT_SEPARATOR = ','.freeze
44
+
45
+ # Replacement for input id interpolation
46
+ #
47
+ # @since x.x.x
48
+ # @api private
49
+ #
50
+ # @see Lotus::Helpers::FormHelper::FormBuilder#_input_id
51
+ INPUT_ID_REPLACEMENT = '-\k<token>'.freeze
52
+
53
+ # Replacement for input value interpolation
54
+ #
55
+ # @since x.x.x
56
+ # @api private
57
+ #
58
+ # @see Lotus::Helpers::FormHelper::FormBuilder#_value
59
+ INPUT_VALUE_REPLACEMENT = '.\k<token>'.freeze
60
+
61
+ # Default value for unchecked check box
62
+ #
63
+ # @since x.x.x
64
+ # @api private
65
+ #
66
+ # @see Lotus::Helpers::FormHelper::FormBuilder#check_box
67
+ DEFAULT_UNCHECKED_VALUE = '0'.freeze
68
+
69
+ # Default value for checked check box
70
+ #
71
+ # @since x.x.x
72
+ # @api private
73
+ #
74
+ # @see Lotus::Helpers::FormHelper::FormBuilder#check_box
75
+ DEFAULT_CHECKED_VALUE = '1'.freeze
76
+
77
+ # ENCTYPE_MULTIPART = 'multipart/form-data'.freeze
78
+
79
+ self.html_node = ::Lotus::Helpers::FormHelper::HtmlNode
80
+
81
+ # Instantiate a form builder
82
+ #
83
+ # @overload initialize(form, attributes, params, &blk)
84
+ # Top level form
85
+ # @param form [Lotus::Helpers:FormHelper::Form] the form
86
+ # @param attributes [::Hash] a set of HTML attributes
87
+ # @param params [Lotus::Action::Params] request params
88
+ # @param blk [Proc] a block that describes the contents of the form
89
+ #
90
+ # @overload initialize(form, attributes, params, &blk)
91
+ # Nested form
92
+ # @param form [Lotus::Helpers:FormHelper::Form] the form
93
+ # @param attributes [Lotus::Helpers::FormHelper::Values] user defined
94
+ # values
95
+ # @param blk [Proc] a block that describes the contents of the form
96
+ #
97
+ # @return [Lotus::Helpers::FormHelper::FormBuilder] the form builder
98
+ #
99
+ # @since x.x.x
100
+ # @api private
101
+ def initialize(form, attributes, context = nil, &blk)
102
+ super()
103
+
104
+ @context = context
105
+ @blk = blk
106
+
107
+ # Nested form
108
+ if @context.nil? && attributes.is_a?(Values)
109
+ @values = attributes
110
+ @attributes = {}
111
+ @name = form
112
+ else
113
+ @form = form
114
+ @name = form.name
115
+ @values = Values.new(form.values, @context.params)
116
+ @attributes = attributes
117
+ @csrf_token = csrf_token
118
+ end
119
+ end
120
+
121
+ # Resolves all the nodes and generates the markup
122
+ #
123
+ # @return [Lotus::Utils::Escape::SafeString] the output
124
+ #
125
+ # @since x.x.x
126
+ # @api private
127
+ #
128
+ # @see Lotus::Helpers::HtmlHelper::HtmlBuilder#to_s
129
+ # @see http://www.rubydoc.info/gems/lotus-utils/Lotus/Utils/Escape/SafeString
130
+ def to_s
131
+ if toplevel?
132
+ _method_override!
133
+ form(@blk, @attributes)
134
+ end
135
+
136
+ super
137
+ end
138
+
139
+ # Nested fields
140
+ #
141
+ # The inputs generated by the wrapped block will be prefixed with the given name
142
+ # It supports infinite levels of nesting.
143
+ #
144
+ # @param name [Symbol] the nested name, it's used to generate input
145
+ # names, ids, and to lookup params to fill values.
146
+ #
147
+ # @since x.x.x
148
+ #
149
+ # @example Basic usage
150
+ # <%=
151
+ # form_for :delivery, routes.deliveries_path do
152
+ # text_field :customer_name
153
+ #
154
+ # fields_for :address do
155
+ # text_field :street
156
+ # end
157
+ #
158
+ # submit 'Create'
159
+ # end
160
+ # %>
161
+ #
162
+ # Output:
163
+ # # <form action="/deliveries" method="POST" accept-charset="utf-8" id="delivery-form">
164
+ # # <input type="text" name="delivery[customer_name]" id="delivery-customer-name" value="">
165
+ # # <input type="text" name="delivery[address][street]" id="delivery-address-street" value="">
166
+ # #
167
+ # # <button type="submit">Create</button>
168
+ # # </form>
169
+ #
170
+ # @example Multiple levels of nesting
171
+ # <%=
172
+ # form_for :delivery, routes.deliveries_path do
173
+ # text_field :customer_name
174
+ #
175
+ # fields_for :address do
176
+ # text_field :street
177
+ #
178
+ # fields_for :location do
179
+ # text_field :city
180
+ # text_field :country
181
+ # end
182
+ # end
183
+ #
184
+ # submit 'Create'
185
+ # end
186
+ # %>
187
+ #
188
+ # Output:
189
+ # # <form action="/deliveries" method="POST" accept-charset="utf-8" id="delivery-form">
190
+ # # <input type="text" name="delivery[customer_name]" id="delivery-customer-name" value="">
191
+ # # <input type="text" name="delivery[address][street]" id="delivery-address-street" value="">
192
+ # # <input type="text" name="delivery[address][location][city]" id="delivery-address-location-city" value="">
193
+ # # <input type="text" name="delivery[address][location][country]" id="delivery-address-location-country" value="">
194
+ # #
195
+ # # <button type="submit">Create</button>
196
+ # # </form>
197
+ def fields_for(name)
198
+ current_name = @name
199
+ @name = _input_name(name)
200
+ yield
201
+ ensure
202
+ @name = current_name
203
+ end
204
+
205
+ # Label tag
206
+ #
207
+ # The first param <tt>content</tt> can be a <tt>Symbol</tt> that represents
208
+ # the target field (Eg. <tt>:extended_title</tt>), or a <tt>String</tt>
209
+ # which is used as it is.
210
+ #
211
+ # @param content [Symbol,String] the field name or a content string
212
+ # @param attributes [Hash] HTML attributes to pass to the label tag
213
+ #
214
+ # @since x.x.x
215
+ #
216
+ # @example Basic usage
217
+ # <%=
218
+ # # ...
219
+ # label :extended_title
220
+ # %>
221
+ #
222
+ # # Output:
223
+ # # <label for="book-extended-title">Extended Title</label>
224
+ #
225
+ # @example Custom content
226
+ # <%=
227
+ # # ...
228
+ # label 'Title', for: :extended_title
229
+ # %>
230
+ #
231
+ # # Output:
232
+ # # <label for="book-extended-title">Title</label>
233
+ #
234
+ # @example Nested fields usage
235
+ # <%=
236
+ # # ...
237
+ # fields_for :address do
238
+ # label :city
239
+ # text_field :city
240
+ # end
241
+ # %>
242
+ #
243
+ # # Output:
244
+ # # <label for="delivery-address-city">City</label>
245
+ # # <input type="text" name="delivery[address][city] id="delivery-address-city" value="">
246
+ def label(content, attributes = {})
247
+ attributes = { for: _for(content, attributes.delete(:for)) }.merge(attributes)
248
+ content = Utils::String.new(content).titleize
249
+
250
+ super(content, attributes)
251
+ end
252
+
253
+ # Check box
254
+ #
255
+ # It renders a check box input.
256
+ #
257
+ # When a form is submitted, browsers don't send the value of unchecked
258
+ # check boxes. If an user unchecks a check box, their browser won't send
259
+ # the unchecked value. On the server side the corresponding value is
260
+ # missing, so the application will assume that the user action never
261
+ # happened.
262
+ #
263
+ # To solve this problem the form renders a hidden field with the
264
+ # "unchecked value". When the user unchecks the input, the browser will
265
+ # ignore it, but it will still send the value of the hidden input. See
266
+ # the examples below.
267
+ #
268
+ # When editing a resource, the form automatically assigns the
269
+ # <tt>checked="checked"</tt> attribute.
270
+ #
271
+ # @param name [Symbol] the input name
272
+ # @param attributes [Hash] HTML attributes to pass to the input tag
273
+ # @option attributes [String] :checked_value (defaults to "1")
274
+ # @option attributes [String] :unchecked_value (defaults to "0")
275
+ #
276
+ # @since x.x.x
277
+ #
278
+ # @example Basic usage
279
+ # <%=
280
+ # check_box :free_shipping
281
+ # %>
282
+ #
283
+ # # Output:
284
+ # # <input type="hidden" name="delivery[free_shipping]" value="0">
285
+ # # <input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="1">
286
+ #
287
+ # @example Specify (un)checked values
288
+ # <%=
289
+ # check_box :free_shipping, checked_value: 'true', unchecked_value: 'false'
290
+ # %>
291
+ #
292
+ # # Output:
293
+ # # <input type="hidden" name="delivery[free_shipping]" value="false">
294
+ # # <input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="true">
295
+ #
296
+ # @example Automatic "checked" attribute
297
+ # # For this example the params are:
298
+ # #
299
+ # # { delivery: { free_shipping: '1' } }
300
+ # <%=
301
+ # check_box :free_shipping
302
+ # %>
303
+ #
304
+ # # Output:
305
+ # # <input type="hidden" name="delivery[free_shipping]" value="0">
306
+ # # <input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="1" checked="checked">
307
+ #
308
+ # @example Force "checked" attribute
309
+ # # For this example the params are:
310
+ # #
311
+ # # { delivery: { free_shipping: '0' } }
312
+ # <%=
313
+ # check_box :free_shipping, checked: 'checked'
314
+ # %>
315
+ #
316
+ # # Output:
317
+ # # <input type="hidden" name="delivery[free_shipping]" value="0">
318
+ # # <input type="checkbox" name="delivery[free_shipping]" id="delivery-free-shipping" value="1" checked="checked">
319
+ #
320
+ # @example Multiple check boxes
321
+ # <%=
322
+ # check_box :languages, name: 'book[languages][]', value: 'italian', id: nil
323
+ # check_box :languages, name: 'book[languages][]', value: 'english', id: nil
324
+ # %>
325
+ #
326
+ # # Output:
327
+ # # <input type="checkbox" name="book[languages][]" value="italian">
328
+ # # <input type="checkbox" name="book[languages][]" value="english">
329
+ #
330
+ # @example Automatic "checked" attribute for multiple check boxes
331
+ # # For this example the params are:
332
+ # #
333
+ # # { book: { languages: ['italian'] } }
334
+ # <%=
335
+ # check_box :languages, name: 'book[languages][]', value: 'italian', id: nil
336
+ # check_box :languages, name: 'book[languages][]', value: 'english', id: nil
337
+ # %>
338
+ #
339
+ # # Output:
340
+ # # <input type="checkbox" name="book[languages][]" value="italian" checked="checked">
341
+ # # <input type="checkbox" name="book[languages][]" value="english">
342
+ def check_box(name, attributes = {})
343
+ _hidden_field_for_check_box( name, attributes)
344
+ input _attributes_for_check_box(name, attributes)
345
+ end
346
+
347
+ # Color input
348
+ #
349
+ # @param name [Symbol] the input name
350
+ # @param attributes [Hash] HTML attributes to pass to the input tag
351
+ #
352
+ # @since x.x.x
353
+ #
354
+ # @example Basic usage
355
+ # <%=
356
+ # # ...
357
+ # color_field :background
358
+ # %>
359
+ #
360
+ # # Output:
361
+ # # <input type="color" name="user[background]" id="user-background" value="">
362
+ def color_field(name, attributes = {})
363
+ input _attributes(:color, name, attributes)
364
+ end
365
+
366
+ # Date input
367
+ #
368
+ # @param name [Symbol] the input name
369
+ # @param attributes [Hash] HTML attributes to pass to the input tag
370
+ #
371
+ # @since x.x.x
372
+ #
373
+ # @example Basic usage
374
+ # <%=
375
+ # # ...
376
+ # date_field :birth_date
377
+ # %>
378
+ #
379
+ # # Output:
380
+ # # <input type="date" name="user[birth_date]" id="user-birth-date" value="">
381
+ def date_field(name, attributes = {})
382
+ input _attributes(:date, name, attributes)
383
+ end
384
+
385
+ # Datetime input
386
+ #
387
+ # @param name [Symbol] the input name
388
+ # @param attributes [Hash] HTML attributes to pass to the input tag
389
+ #
390
+ # @since x.x.x
391
+ #
392
+ # @example Basic usage
393
+ # <%=
394
+ # # ...
395
+ # datetime_field :delivered_at
396
+ # %>
397
+ #
398
+ # # Output:
399
+ # # <input type="datetime" name="delivery[delivered_at]" id="delivery-delivered-at" value="">
400
+ def datetime_field(name, attributes = {})
401
+ input _attributes(:datetime, name, attributes)
402
+ end
403
+
404
+ # Datetime Local input
405
+ #
406
+ # @param name [Symbol] the input name
407
+ # @param attributes [Hash] HTML attributes to pass to the input tag
408
+ #
409
+ # @since x.x.x
410
+ #
411
+ # @example Basic usage
412
+ # <%=
413
+ # # ...
414
+ # datetime_local_field :delivered_at
415
+ # %>
416
+ #
417
+ # # Output:
418
+ # # <input type="datetime-local" name="delivery[delivered_at]" id="delivery-delivered-at" value="">
419
+ def datetime_local_field(name, attributes = {})
420
+ input _attributes(:'datetime-local', name, attributes)
421
+ end
422
+
423
+ # Email input
424
+ #
425
+ # @param name [Symbol] the input name
426
+ # @param attributes [Hash] HTML attributes to pass to the input tag
427
+ #
428
+ # @since x.x.x
429
+ #
430
+ # @example Basic usage
431
+ # <%=
432
+ # # ...
433
+ # email_field :email
434
+ # %>
435
+ #
436
+ # # Output:
437
+ # # <input type="email" name="user[email]" id="user-email" value="">
438
+ def email_field(name, attributes = {})
439
+ input _attributes(:email, name, attributes)
440
+ end
441
+
442
+ # Hidden input
443
+ #
444
+ # @param name [Symbol] the input name
445
+ # @param attributes [Hash] HTML attributes to pass to the input tag
446
+ #
447
+ # @since x.x.x
448
+ #
449
+ # @example Basic usage
450
+ # <%=
451
+ # # ...
452
+ # hidden_field :customer_id
453
+ # %>
454
+ #
455
+ # # Output:
456
+ # # <input type="hidden" name="delivery[customer_id]" id="delivery-customer-id" value="">
457
+ def hidden_field(name, attributes = {})
458
+ input _attributes(:hidden, name, attributes)
459
+ end
460
+
461
+ # File input
462
+ #
463
+ # PLEASE REMEMBER TO ADD <tt>enctype: 'multipart/form-data'</tt> ATTRIBUTE TO THE FORM
464
+ #
465
+ # @param name [Symbol] the input name
466
+ # @param attributes [Hash] HTML attributes to pass to the input tag
467
+ # @option attributes [String,Array] :accept Optional set of accepted MIME Types
468
+ #
469
+ # @since x.x.x
470
+ #
471
+ # @example Basic usage
472
+ # <%=
473
+ # # ...
474
+ # file_field :avatar
475
+ # %>
476
+ #
477
+ # # Output:
478
+ # # <input type="file" name="user[avatar]" id="user-avatar">
479
+ #
480
+ # @example Accepted mime types
481
+ # <%=
482
+ # # ...
483
+ # file_field :resume, accept: 'application/pdf,application/ms-word'
484
+ # %>
485
+ #
486
+ # # Output:
487
+ # # <input type="file" name="user[resume]" id="user-resume" accept="application/pdf,application/ms-word">
488
+ #
489
+ # @example Accepted mime types (as array)
490
+ # <%=
491
+ # # ...
492
+ # file_field :resume, accept: ['application/pdf', 'application/ms-word']
493
+ # %>
494
+ #
495
+ # # Output:
496
+ # # <input type="file" name="user[resume]" id="user-resume" accept="application/pdf,application/ms-word">
497
+ def file_field(name, attributes = {})
498
+ attributes[:accept] = Array(attributes[:accept]).join(ACCEPT_SEPARATOR) if attributes.key?(:accept)
499
+ attributes = { type: :file, name: _input_name(name), id: _input_id(name) }.merge(attributes)
500
+
501
+ input(attributes)
502
+ end
503
+
504
+ # Text input
505
+ #
506
+ # @param name [Symbol] the input name
507
+ # @param attributes [Hash] HTML attributes to pass to the input tag
508
+ #
509
+ # @since x.x.x
510
+ #
511
+ # @example Basic usage
512
+ # <%=
513
+ # # ...
514
+ # text_field :first_name
515
+ # %>
516
+ #
517
+ # # Output:
518
+ # # <input type="text" name="user[first_name]" id="user-first-name" value="">
519
+ def text_field(name, attributes = {})
520
+ input _attributes(:text, name, attributes)
521
+ end
522
+ alias_method :input_text, :text_field
523
+
524
+ # Radio input
525
+ #
526
+ # If request params have a value that corresponds to the given value,
527
+ # it automatically sets the <tt>checked</tt> attribute.
528
+ # This Lotus::Controller integration happens without any developer intervention.
529
+ #
530
+ # @param name [Symbol] the input name
531
+ # @param value [String] the input value
532
+ # @param attributes [Hash] HTML attributes to pass to the input tag
533
+ #
534
+ # @since x.x.x
535
+ #
536
+ # @example Basic usage
537
+ # <%=
538
+ # # ...
539
+ # radio_button :category, 'Fiction'
540
+ # radio_button :category, 'Non-Fiction'
541
+ # %>
542
+ #
543
+ # # Output:
544
+ # # <input type="radio" name="book[category]" value="Fiction">
545
+ # # <input type="radio" name="book[category]" value="Non-Fiction">
546
+ #
547
+ # @example Automatic checked value
548
+ # # Given the following params:
549
+ # #
550
+ # # book: {
551
+ # # category: 'Non-Fiction'
552
+ # # }
553
+ #
554
+ # <%=
555
+ # # ...
556
+ # radio_button :category, 'Fiction'
557
+ # radio_button :category, 'Non-Fiction'
558
+ # %>
559
+ #
560
+ # # Output:
561
+ # # <input type="radio" name="book[category]" value="Fiction">
562
+ # # <input type="radio" name="book[category]" value="Non-Fiction" checked="checked">
563
+ def radio_button(name, value, attributes = {})
564
+ attributes = { type: :radio, name: _input_name(name), value: value }.merge(attributes)
565
+ attributes[:checked] = CHECKED if _value(name) == value
566
+ input(attributes)
567
+ end
568
+
569
+ # Password input
570
+ #
571
+ # @param name [Symbol] the input name
572
+ # @param attributes [Hash] HTML attributes to pass to the input tag
573
+ #
574
+ # @since x.x.x
575
+ #
576
+ # @example Basic usage
577
+ # <%=
578
+ # # ...
579
+ # password_field :password
580
+ # %>
581
+ #
582
+ # # Output:
583
+ # # <input type="password" name="signup[password]" id="signup-password" value="">
584
+ def password_field(name, attributes = {})
585
+ input({ type: :password, name: _input_name(name), id: _input_id(name), value: nil }.merge(attributes))
586
+ end
587
+
588
+ # Select input
589
+ #
590
+ # @param name [Symbol] the input name
591
+ # @param values [Hash] a Hash to generate <tt><option></tt> tags.
592
+ # Keys correspond to <tt>value</tt> and values correspond to the content.
593
+ # @param attributes [Hash] HTML attributes to pass to the input tag
594
+ #
595
+ # If request params have a value that corresponds to one of the given values,
596
+ # it automatically sets the <tt>selected</tt> attribute on the <tt><option></tt> tag.
597
+ # This Lotus::Controller integration happens without any developer intervention.
598
+ #
599
+ # @since x.x.x
600
+ #
601
+ # @example Basic usage
602
+ # <%=
603
+ # # ...
604
+ # values = Hash['it' => 'Italy', 'us' => 'United States']
605
+ # select :stores, values
606
+ # %>
607
+ #
608
+ # # Output:
609
+ # # <select name="book[store]" id="book-store">
610
+ # # <option value="it">Italy</option>
611
+ # # <option value="us">United States</option>
612
+ # # </select>
613
+ #
614
+ # @example Automatic selected option
615
+ # # Given the following params:
616
+ # #
617
+ # # book: {
618
+ # # store: 'it'
619
+ # # }
620
+ #
621
+ # <%=
622
+ # # ...
623
+ # values = Hash['it' => 'Italy', 'us' => 'United States']
624
+ # select :stores, values
625
+ # %>
626
+ #
627
+ # # Output:
628
+ # # <select name="book[store]" id="book-store">
629
+ # # <option value="it" selected="selected">Italy</option>
630
+ # # <option value="us">United States</option>
631
+ # # </select>
632
+ def select(name, values, attributes = {})
633
+ options = attributes.delete(:options) || {}
634
+ attributes = { name: _input_name(name), id: _input_id(name) }.merge(attributes)
635
+
636
+ super(attributes) do
637
+ values.each do |value, content|
638
+ if _value(name) == value
639
+ option(content, {value: value, selected: SELECTED}.merge(options))
640
+ else
641
+ option(content, {value: value}.merge(options))
642
+ end
643
+ end
644
+ end
645
+ end
646
+
647
+ # Submit button
648
+ #
649
+ # @param content [String] The content
650
+ # @param attributes [Hash] HTML attributes to pass to the button tag
651
+ #
652
+ # @since x.x.x
653
+ #
654
+ # @example Basic usage
655
+ # <%=
656
+ # # ...
657
+ # submit 'Create'
658
+ # %>
659
+ #
660
+ # # Output:
661
+ # # <button type="submit">Create</button>
662
+ def submit(content, attributes = {})
663
+ attributes = { type: :submit }.merge(attributes)
664
+ button(content, attributes)
665
+ end
666
+
667
+ protected
668
+ # A set of options to pass to the sub form helpers.
669
+ #
670
+ # @api private
671
+ # @since x.x.x
672
+ def options
673
+ Hash[name: @name, values: @values, verb: @verb, csrf_token: @csrf_token]
674
+ end
675
+
676
+ private
677
+ # Check the current builder is top-level
678
+ #
679
+ # @api private
680
+ # @since x.x.x
681
+ def toplevel?
682
+ @attributes.any?
683
+ end
684
+
685
+ # Prepare for method override
686
+ #
687
+ # @api private
688
+ # @since x.x.x
689
+ def _method_override!
690
+ verb = (@attributes.fetch(:method) { DEFAULT_METHOD }).to_s.upcase
691
+
692
+ if BROWSER_METHODS.include?(verb)
693
+ @attributes[:method] = verb
694
+ else
695
+ @attributes[:method] = DEFAULT_METHOD
696
+ @verb = verb
697
+ end
698
+ end
699
+
700
+ # Return CSRF Protection token from view context
701
+ #
702
+ # @api private
703
+ # @since x.x.x
704
+ def csrf_token
705
+ @context.csrf_token if @context.respond_to?(:csrf_token)
706
+ end
707
+
708
+ # Return a set of default HTML attributes
709
+ #
710
+ # @api private
711
+ # @since x.x.x
712
+ def _attributes(type, name, attributes)
713
+ { type: type, name: _input_name(name), id: _input_id(name), value: _value(name) }.merge(attributes)
714
+ end
715
+
716
+ # Input <tt>name</tt> HTML attribute
717
+ #
718
+ # @api private
719
+ # @since x.x.x
720
+ def _input_name(name)
721
+ "#{ @name }[#{ name }]"
722
+ end
723
+
724
+ # Input <tt>id</tt> HTML attribute
725
+ #
726
+ # @api private
727
+ # @since x.x.x
728
+ def _input_id(name)
729
+ name = _input_name(name).gsub(/\[(?<token>[[[:word:]]\-]*)\]/, INPUT_ID_REPLACEMENT)
730
+ Utils::String.new(name).dasherize
731
+ end
732
+
733
+ # Input <tt>value</tt> HTML attribute
734
+ #
735
+ # @api private
736
+ # @since x.x.x
737
+ def _value(name)
738
+ name = _input_name(name).gsub(/\[(?<token>[[:word:]]*)\]/, INPUT_VALUE_REPLACEMENT)
739
+ @values.get(name)
740
+ end
741
+
742
+ # Input <tt>for</tt> HTML attribute
743
+ #
744
+ # @api private
745
+ # @since x.x.x
746
+ def _for(content, name)
747
+ _input_id(name || content)
748
+ end
749
+
750
+ # Hidden field for check box
751
+ #
752
+ # @api private
753
+ # @since x.x.x
754
+ #
755
+ # @see Lotus::Helpers::FormHelper::FormBuilder#check_box
756
+ def _hidden_field_for_check_box(name, attributes)
757
+ if attributes[:value].nil? || !attributes[:unchecked_value].nil?
758
+ input({
759
+ type: :hidden,
760
+ name: attributes[:name] || _input_name(name),
761
+ value: attributes.delete(:unchecked_value) || DEFAULT_UNCHECKED_VALUE
762
+ })
763
+ end
764
+ end
765
+
766
+ # HTML attributes for check box
767
+ #
768
+ # @api private
769
+ # @since x.x.x
770
+ #
771
+ # @see Lotus::Helpers::FormHelper::FormBuilder#check_box
772
+ def _attributes_for_check_box(name, attributes)
773
+ attributes = {
774
+ type: :checkbox,
775
+ name: _input_name(name),
776
+ id: _input_id(name),
777
+ value: attributes.delete(:checked_value) || DEFAULT_CHECKED_VALUE
778
+ }.merge(attributes)
779
+
780
+ value = _value(name)
781
+ attributes[:checked] = CHECKED if value &&
782
+ ( value == attributes[:value] || value.include?(attributes[:value]) )
783
+
784
+ attributes
785
+ end
786
+ end
787
+ end
788
+ end
789
+ end
790
+