lotus-helpers 0.1.0 → 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.
@@ -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
+