hanami-helpers 0.3.0 → 0.4.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 +4 -4
- data/CHANGELOG.md +14 -0
- data/hanami-helpers.gemspec +7 -6
- data/lib/hanami-helpers.rb +1 -1
- data/lib/hanami/helpers/escape_helper.rb +5 -4
- data/lib/hanami/helpers/form_helper.rb +12 -10
- data/lib/hanami/helpers/form_helper/form_builder.rb +147 -22
- data/lib/hanami/helpers/form_helper/html_node.rb +3 -2
- data/lib/hanami/helpers/form_helper/values.rb +21 -5
- data/lib/hanami/helpers/html_helper.rb +1 -0
- data/lib/hanami/helpers/html_helper/empty_html_node.rb +53 -13
- data/lib/hanami/helpers/html_helper/html_builder.rb +121 -121
- data/lib/hanami/helpers/html_helper/html_fragment.rb +3 -1
- data/lib/hanami/helpers/html_helper/html_node.rb +8 -6
- data/lib/hanami/helpers/html_helper/text_node.rb +2 -0
- data/lib/hanami/helpers/link_to_helper.rb +2 -2
- data/lib/hanami/helpers/number_formatting_helper.rb +3 -0
- data/lib/hanami/helpers/routing_helper.rb +4 -2
- data/lib/hanami/helpers/version.rb +1 -1
- metadata +8 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e90f277e6ff4d461bd7ebcc45e48de6c03f91e70
|
4
|
+
data.tar.gz: 8d97b52cf45b16454acf597a6fe198b3a549148a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 21d4b2160f0d6af94d099ec8f765bbcce309b22623aff0ce3190f50b7fb2fec228fde3b6f330a47242455ab7989144e8c04b5a146170399d74f914ba0facc79f
|
7
|
+
data.tar.gz: f898b3a411eb8d77e776a398ef2873bc6b6e8ef39fffd59602f8d0b7cd53a5662ea767665a95e7da228271bb3f16cf635f3df12d28feceed507177b2e621134c
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
# Hanami::Helpers
|
2
2
|
View helpers for Ruby web applications
|
3
3
|
|
4
|
+
## v0.4.0 - 2016-07-22
|
5
|
+
### Added
|
6
|
+
- [Luca Guidi] Allow `link_to` to be concat with other helpers. Eg `link_to(...) + link_to(...)`, `span(...) + link_to(...)`.
|
7
|
+
- [Anton Davydov] Support blank `<option>` tag for `select` form helper. Eg. `select :store, [...], options: { prompt: '' }`
|
8
|
+
- [Sebastjan Hribar] Support selected `<option>` for `select` form helper. Eg. `select :store, [...], options: { selected: 'it' }`
|
9
|
+
- [Cang Ta] Added `datalist` form helper
|
10
|
+
|
11
|
+
### Changed
|
12
|
+
– [Luca Guidi] Drop support for Ruby 2.0 and 2.1. Official support for JRuby 9.0.5.0+.
|
13
|
+
- [Luca Guidi] Inverted options (label, value) for `select` form helper. Now the syntax is `select :store, { 'Italy' => 'it', 'United States' => 'us' }`
|
14
|
+
|
15
|
+
### Fixed
|
16
|
+
– [Nikolay Shebanov] Explicitly require some `hanami-utils` dependencies
|
17
|
+
|
4
18
|
## v0.3.0 - 2016-01-22
|
5
19
|
### Changed
|
6
20
|
- [Luca Guidi] Renamed the project
|
data/hanami-helpers.gemspec
CHANGED
@@ -8,20 +8,21 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Hanami::Helpers::VERSION
|
9
9
|
spec.authors = ['Luca Guidi', 'Trung Lê', 'Alfonso Uceda']
|
10
10
|
spec.email = ['me@lucaguidi.com', 'trung.le@ruby-journal.com', 'uceda73@gmail.com']
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
11
|
+
spec.summary = 'Hanami helpers'
|
12
|
+
spec.description = 'View helpers for Ruby applications'
|
13
13
|
spec.homepage = 'http://hanamirb.org'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
16
|
-
spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-helpers.gemspec`.split($/)
|
16
|
+
spec.files = `git ls-files -- lib/* CHANGELOG.md LICENSE.md README.md hanami-helpers.gemspec`.split($/) # rubocop:disable Style/SpecialGlobalVars
|
17
|
+
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
20
|
spec.require_paths = ['lib']
|
20
|
-
spec.required_ruby_version = '>= 2.
|
21
|
+
spec.required_ruby_version = '>= 2.2.0'
|
21
22
|
|
22
|
-
spec.add_dependency 'hanami-utils', '~> 0.
|
23
|
+
spec.add_dependency 'hanami-utils', '~> 0.8'
|
23
24
|
|
24
25
|
spec.add_development_dependency 'bundler', '~> 1.6'
|
25
|
-
spec.add_development_dependency 'rake', '~>
|
26
|
+
spec.add_development_dependency 'rake', '~> 11'
|
26
27
|
spec.add_development_dependency 'minitest', '~> 5.5'
|
27
28
|
end
|
data/lib/hanami-helpers.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require 'hanami/helpers'
|
1
|
+
require 'hanami/helpers' # rubocop:disable Style/FileName
|
@@ -4,7 +4,7 @@ module Hanami
|
|
4
4
|
module Helpers
|
5
5
|
# Escape helpers
|
6
6
|
#
|
7
|
-
# You can include this module inside your view and
|
7
|
+
# You can include this module inside your view and
|
8
8
|
# the view will have access all methods.
|
9
9
|
#
|
10
10
|
# By including <tt>Hanami::Helpers::EscapeHelper</tt> it will inject private
|
@@ -13,6 +13,7 @@ module Hanami
|
|
13
13
|
# @since 0.1.0
|
14
14
|
module EscapeHelper
|
15
15
|
private
|
16
|
+
|
16
17
|
# Escape the given HTML tag content.
|
17
18
|
#
|
18
19
|
# This should be used only for untrusted contents: user input.
|
@@ -75,7 +76,7 @@ module Hanami
|
|
75
76
|
end
|
76
77
|
|
77
78
|
# @since 0.1.0
|
78
|
-
|
79
|
+
alias h escape_html
|
79
80
|
|
80
81
|
# Escape the given HTML tag attribute.
|
81
82
|
#
|
@@ -147,7 +148,7 @@ module Hanami
|
|
147
148
|
end
|
148
149
|
|
149
150
|
# @since 0.1.0
|
150
|
-
|
151
|
+
alias ha escape_html_attribute
|
151
152
|
|
152
153
|
# Escape an URL to be used in HTML attributes
|
153
154
|
#
|
@@ -225,7 +226,7 @@ module Hanami
|
|
225
226
|
end
|
226
227
|
|
227
228
|
# @since 0.1.0
|
228
|
-
|
229
|
+
alias hu escape_url
|
229
230
|
|
230
231
|
# Bypass escape.
|
231
232
|
#
|
@@ -28,22 +28,24 @@ module Hanami
|
|
28
28
|
#
|
29
29
|
# Supported tags and inputs:
|
30
30
|
#
|
31
|
+
# * <tt>check_box</tt>
|
31
32
|
# * <tt>color_field</tt>
|
32
33
|
# * <tt>date_field</tt>
|
33
34
|
# * <tt>datetime_field</tt>
|
34
35
|
# * <tt>datetime_local_field</tt>
|
35
36
|
# * <tt>email_field</tt>
|
36
|
-
# * <tt>hidden_field</tt>
|
37
|
-
# * <tt>file_field</tt>
|
38
37
|
# * <tt>fields_for</tt>
|
38
|
+
# * <tt>file_field</tt>
|
39
39
|
# * <tt>form_for</tt>
|
40
|
+
# * <tt>hidden_field</tt>
|
40
41
|
# * <tt>label</tt>
|
41
|
-
# * <tt>
|
42
|
-
# * <tt>text_field</tt>
|
42
|
+
# * <tt>number_field</tt>
|
43
43
|
# * <tt>password_field</tt>
|
44
44
|
# * <tt>radio_button</tt>
|
45
45
|
# * <tt>select</tt>
|
46
46
|
# * <tt>submit</tt>
|
47
|
+
# * <tt>text_area</tt>
|
48
|
+
# * <tt>text_field</tt>
|
47
49
|
#
|
48
50
|
# @since 0.2.0
|
49
51
|
#
|
@@ -395,13 +397,13 @@ module Hanami
|
|
395
397
|
# # </form>
|
396
398
|
def form_for(name, url, options = {}, &blk)
|
397
399
|
form = if name.is_a?(Form)
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
400
|
+
options = url
|
401
|
+
name
|
402
|
+
else
|
403
|
+
Form.new(name, url, options.delete(:values))
|
404
|
+
end
|
403
405
|
|
404
|
-
attributes = { action: form.url, method: form.verb, :'accept-charset' => DEFAULT_CHARSET, id: "#{
|
406
|
+
attributes = { action: form.url, method: form.verb, :'accept-charset' => DEFAULT_CHARSET, id: "#{form.name}-form" }.merge(options)
|
405
407
|
FormBuilder.new(form, attributes, self, &blk)
|
406
408
|
end
|
407
409
|
|
@@ -11,18 +11,18 @@ module Hanami
|
|
11
11
|
# @since 0.2.0
|
12
12
|
#
|
13
13
|
# @see Hanami::Helpers::HtmlHelper::HtmlBuilder
|
14
|
-
class FormBuilder < ::Hanami::Helpers::HtmlHelper::HtmlBuilder
|
14
|
+
class FormBuilder < ::Hanami::Helpers::HtmlHelper::HtmlBuilder # rubocop:disable Metrics/ClassLength
|
15
15
|
# Set of HTTP methods that are understood by web browsers
|
16
16
|
#
|
17
17
|
# @since 0.2.0
|
18
18
|
# @api private
|
19
|
-
BROWSER_METHODS =
|
19
|
+
BROWSER_METHODS = %w(GET POST).freeze
|
20
20
|
|
21
21
|
# Set of HTTP methods that should NOT generate CSRF token
|
22
22
|
#
|
23
23
|
# @since 0.2.0
|
24
24
|
# @api private
|
25
|
-
EXCLUDED_CSRF_METHODS =
|
25
|
+
EXCLUDED_CSRF_METHODS = %w(GET).freeze
|
26
26
|
|
27
27
|
# Checked attribute value
|
28
28
|
#
|
@@ -104,11 +104,13 @@ module Hanami
|
|
104
104
|
#
|
105
105
|
# @since 0.2.0
|
106
106
|
# @api private
|
107
|
-
def initialize(form, attributes, context = nil, &blk)
|
107
|
+
def initialize(form, attributes, context = nil, &blk) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
108
108
|
super()
|
109
109
|
|
110
|
-
@context
|
111
|
-
@blk
|
110
|
+
@context = context
|
111
|
+
@blk = blk
|
112
|
+
@verb = nil
|
113
|
+
@csrf_token = nil
|
112
114
|
|
113
115
|
# Nested form
|
114
116
|
if @context.nil? && attributes.is_a?(Values)
|
@@ -361,7 +363,7 @@ module Hanami
|
|
361
363
|
# # <input type="checkbox" name="book[languages][]" value="italian" checked="checked">
|
362
364
|
# # <input type="checkbox" name="book[languages][]" value="english">
|
363
365
|
def check_box(name, attributes = {})
|
364
|
-
_hidden_field_for_check_box(
|
366
|
+
_hidden_field_for_check_box(name, attributes)
|
365
367
|
input _attributes_for_check_box(name, attributes)
|
366
368
|
end
|
367
369
|
|
@@ -486,6 +488,7 @@ module Hanami
|
|
486
488
|
# @param name [Symbol] the input name
|
487
489
|
# @param attributes [Hash] HTML attributes to pass to the input tag
|
488
490
|
# @option attributes [String,Array] :accept Optional set of accepted MIME Types
|
491
|
+
# @option attributes [TrueClass,FalseClass] :multiple Optional, allow multiple file upload
|
489
492
|
#
|
490
493
|
# @since 0.2.0
|
491
494
|
#
|
@@ -515,6 +518,15 @@ module Hanami
|
|
515
518
|
#
|
516
519
|
# # Output:
|
517
520
|
# # <input type="file" name="user[resume]" id="user-resume" accept="application/pdf,application/ms-word">
|
521
|
+
#
|
522
|
+
# @example Accepted multiple file upload (as array)
|
523
|
+
# <%=
|
524
|
+
# # ...
|
525
|
+
# file_field :resume, multiple: true
|
526
|
+
# %>
|
527
|
+
#
|
528
|
+
# # Output:
|
529
|
+
# # <input type="file" name="user[resume]" id="user-resume" multiple="multiple">
|
518
530
|
def file_field(name, attributes = {})
|
519
531
|
attributes[:accept] = Array(attributes[:accept]).join(ACCEPT_SEPARATOR) if attributes.key?(:accept)
|
520
532
|
attributes = { type: :file, name: _input_name(name), id: _input_id(name) }.merge(attributes)
|
@@ -609,7 +621,7 @@ module Hanami
|
|
609
621
|
content = nil
|
610
622
|
end
|
611
623
|
|
612
|
-
attributes = {name: _input_name(name), id: _input_id(name)}.merge(attributes)
|
624
|
+
attributes = { name: _input_name(name), id: _input_id(name) }.merge(attributes)
|
613
625
|
textarea(content || _value(name), attributes)
|
614
626
|
end
|
615
627
|
|
@@ -631,7 +643,7 @@ module Hanami
|
|
631
643
|
def text_field(name, attributes = {})
|
632
644
|
input _attributes(:text, name, attributes)
|
633
645
|
end
|
634
|
-
|
646
|
+
alias input_text text_field
|
635
647
|
|
636
648
|
# Radio input
|
637
649
|
#
|
@@ -701,7 +713,7 @@ module Hanami
|
|
701
713
|
#
|
702
714
|
# @param name [Symbol] the input name
|
703
715
|
# @param values [Hash] a Hash to generate <tt><option></tt> tags.
|
704
|
-
#
|
716
|
+
# Values correspond to <tt>value</tt> and keys correspond to the content.
|
705
717
|
# @param attributes [Hash] HTML attributes to pass to the input tag
|
706
718
|
#
|
707
719
|
# If request params have a value that corresponds to one of the given values,
|
@@ -713,7 +725,7 @@ module Hanami
|
|
713
725
|
# @example Basic usage
|
714
726
|
# <%=
|
715
727
|
# # ...
|
716
|
-
# values = Hash['
|
728
|
+
# values = Hash['Italy' => 'it', 'United States' => 'us']
|
717
729
|
# select :stores, values
|
718
730
|
# %>
|
719
731
|
#
|
@@ -741,21 +753,132 @@ module Hanami
|
|
741
753
|
# # <option value="it" selected="selected">Italy</option>
|
742
754
|
# # <option value="us">United States</option>
|
743
755
|
# # </select>
|
744
|
-
|
745
|
-
|
756
|
+
#
|
757
|
+
# @example Prompt option
|
758
|
+
# <%=
|
759
|
+
# # ...
|
760
|
+
# values = Hash['it' => 'Italy', 'us' => 'United States']
|
761
|
+
# select :stores, values, options: {prompt: 'Select a store'}
|
762
|
+
# %>
|
763
|
+
#
|
764
|
+
# # Output:
|
765
|
+
# # <select name="book[store]" id="book-store">
|
766
|
+
# # <option>Select a store</option>
|
767
|
+
# # <option value="it">Italy</option>
|
768
|
+
# # <option value="us">United States</option>
|
769
|
+
# # </select>
|
770
|
+
#
|
771
|
+
# @example Selected option
|
772
|
+
# <%=
|
773
|
+
# # ...
|
774
|
+
# values = Hash['it' => 'Italy', 'us' => 'United States']
|
775
|
+
# select :stores, values, options: {selected: book.store}
|
776
|
+
# %>
|
777
|
+
#
|
778
|
+
# # Output:
|
779
|
+
# # <select name="book[store]" id="book-store">
|
780
|
+
# # <option value="it" selected="selected">Italy</option>
|
781
|
+
# # <option value="us">United States</option>
|
782
|
+
# # </select>
|
783
|
+
def select(name, values, attributes = {}) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
784
|
+
options = attributes.delete(:options) { {} }
|
746
785
|
attributes = { name: _input_name(name), id: _input_id(name) }.merge(attributes)
|
786
|
+
prompt = options.delete(:prompt)
|
787
|
+
selected = options.delete(:selected)
|
747
788
|
|
748
789
|
super(attributes) do
|
749
|
-
|
750
|
-
|
751
|
-
|
790
|
+
option(prompt) unless prompt.nil?
|
791
|
+
|
792
|
+
values.each do |content, value|
|
793
|
+
if selected == value || _value(name) == value
|
794
|
+
option(content, { value: value, selected: SELECTED }.merge(options))
|
752
795
|
else
|
753
|
-
option(content, {value: value}.merge(options))
|
796
|
+
option(content, { value: value }.merge(options))
|
754
797
|
end
|
755
798
|
end
|
756
799
|
end
|
757
800
|
end
|
758
801
|
|
802
|
+
# Datalist input
|
803
|
+
#
|
804
|
+
# @param name [Symbol] the input name
|
805
|
+
# @param values [Array,Hash] a collection that is transformed into <tt><option></tt> tags.
|
806
|
+
# @param list [String] the name of list for the text input, it's also the id of datalist
|
807
|
+
# @param attributes [Hash] HTML attributes to pass to the input tag
|
808
|
+
#
|
809
|
+
# @since 0.4.0
|
810
|
+
#
|
811
|
+
# @example Basic Usage
|
812
|
+
# <%=
|
813
|
+
# # ...
|
814
|
+
# values = ['Italy', 'United States']
|
815
|
+
# datalist :stores, values, 'books'
|
816
|
+
# %>
|
817
|
+
#
|
818
|
+
# # Output:
|
819
|
+
# # <input type="text" name="book[store]" id="book-store" value="" list="books">
|
820
|
+
# # <datalist id="books">
|
821
|
+
# # <option value="Italy"></option>
|
822
|
+
# # <option value="United States"></option>
|
823
|
+
# # </datalist>
|
824
|
+
#
|
825
|
+
# @example Options As Hash
|
826
|
+
# <%=
|
827
|
+
# # ...
|
828
|
+
# values = Hash['Italy' => 'it', 'United States' => 'us']
|
829
|
+
# datalist :stores, values, 'books'
|
830
|
+
# %>
|
831
|
+
#
|
832
|
+
# # Output:
|
833
|
+
# # <input type="text" name="book[store]" id="book-store" value="" list="books">
|
834
|
+
# # <datalist id="books">
|
835
|
+
# # <option value="Italy">it</option>
|
836
|
+
# # <option value="United States">us</option>
|
837
|
+
# # </datalist>
|
838
|
+
#
|
839
|
+
# @example Specify Custom Attributes For Datalist Input
|
840
|
+
# <%=
|
841
|
+
# # ...
|
842
|
+
# values = ['Italy', 'United States']
|
843
|
+
# datalist :stores, values, 'books', datalist: { class: 'form-control' }
|
844
|
+
# %>
|
845
|
+
#
|
846
|
+
# # Output:
|
847
|
+
# # <input type="text" name="book[store]" id="book-store" value="" list="books">
|
848
|
+
# # <datalist id="books" class="form-control">
|
849
|
+
# # <option value="Italy"></option>
|
850
|
+
# # <option value="United States"></option>
|
851
|
+
# # </datalist>
|
852
|
+
#
|
853
|
+
# @example Specify Custom Attributes For Options List
|
854
|
+
# <%=
|
855
|
+
# # ...
|
856
|
+
# values = ['Italy', 'United States']
|
857
|
+
# datalist :stores, values, 'books', options: { class: 'form-control' }
|
858
|
+
# %>
|
859
|
+
#
|
860
|
+
# # Output:
|
861
|
+
# # <input type="text" name="book[store]" id="book-store" value="" list="books">
|
862
|
+
# # <datalist id="books">
|
863
|
+
# # <option value="Italy" class="form-control"></option>
|
864
|
+
# # <option value="United States" class="form-control"></option>
|
865
|
+
# # </datalist>
|
866
|
+
def datalist(name, values, list, attributes = {}) # rubocop:disable Metrics/MethodLength
|
867
|
+
attrs = attributes.dup
|
868
|
+
options = attrs.delete(:options) || {}
|
869
|
+
datalist = attrs.delete(:datalist) || {}
|
870
|
+
|
871
|
+
attrs[:list] = list
|
872
|
+
datalist[:id] = list
|
873
|
+
|
874
|
+
text_field(name, attrs)
|
875
|
+
super(datalist) do
|
876
|
+
values.each do |value, content|
|
877
|
+
option(content, { value: value }.merge(options))
|
878
|
+
end
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
759
882
|
# Submit button
|
760
883
|
#
|
761
884
|
# @param content [String] The content
|
@@ -777,6 +900,7 @@ module Hanami
|
|
777
900
|
end
|
778
901
|
|
779
902
|
protected
|
903
|
+
|
780
904
|
# A set of options to pass to the sub form helpers.
|
781
905
|
#
|
782
906
|
# @api private
|
@@ -786,6 +910,7 @@ module Hanami
|
|
786
910
|
end
|
787
911
|
|
788
912
|
private
|
913
|
+
|
789
914
|
# Check the current builder is top-level
|
790
915
|
#
|
791
916
|
# @api private
|
@@ -835,7 +960,7 @@ module Hanami
|
|
835
960
|
# @api private
|
836
961
|
# @since 0.2.0
|
837
962
|
def _input_name(name)
|
838
|
-
"#{
|
963
|
+
"#{@name}[#{name}]"
|
839
964
|
end
|
840
965
|
|
841
966
|
# Input <tt>id</tt> HTML attribute
|
@@ -877,11 +1002,11 @@ module Hanami
|
|
877
1002
|
# @see Hanami::Helpers::FormHelper::FormBuilder#check_box
|
878
1003
|
def _hidden_field_for_check_box(name, attributes)
|
879
1004
|
if attributes[:value].nil? || !attributes[:unchecked_value].nil?
|
880
|
-
input(
|
1005
|
+
input(
|
881
1006
|
type: :hidden,
|
882
1007
|
name: attributes[:name] || _input_name(name),
|
883
1008
|
value: attributes.delete(:unchecked_value) || DEFAULT_UNCHECKED_VALUE
|
884
|
-
|
1009
|
+
)
|
885
1010
|
end
|
886
1011
|
end
|
887
1012
|
|
@@ -900,8 +1025,8 @@ module Hanami
|
|
900
1025
|
}.merge(attributes)
|
901
1026
|
|
902
1027
|
value = _value(name)
|
903
|
-
attributes[:checked] = CHECKED if value &&
|
904
|
-
|
1028
|
+
attributes[:checked] = CHECKED if !value.nil? &&
|
1029
|
+
(value == attributes[:value] || value.include?(attributes[:value]))
|
905
1030
|
|
906
1031
|
attributes
|
907
1032
|
end
|
@@ -34,6 +34,7 @@ module Hanami
|
|
34
34
|
end
|
35
35
|
|
36
36
|
private
|
37
|
+
|
37
38
|
# Resolve the (nested) content
|
38
39
|
#
|
39
40
|
# @return [String] the content
|
@@ -68,9 +69,9 @@ module Hanami
|
|
68
69
|
def _csrf_protection!
|
69
70
|
return if @csrf_token.nil?
|
70
71
|
|
71
|
-
|
72
|
+
csrf_token = @csrf_token
|
72
73
|
@builder.resolve do
|
73
|
-
input(type: :hidden, name: FormHelper::CSRF_TOKEN, value:
|
74
|
+
input(type: :hidden, name: FormHelper::CSRF_TOKEN, value: csrf_token)
|
74
75
|
end
|
75
76
|
end
|
76
77
|
end
|
@@ -3,19 +3,37 @@ require 'hanami/utils/hash'
|
|
3
3
|
module Hanami
|
4
4
|
module Helpers
|
5
5
|
module FormHelper
|
6
|
+
# Values from params and form helpers.
|
7
|
+
#
|
8
|
+
# It's responsible to populate input values with data coming from params
|
9
|
+
# and inline values specified via form helpers like `text_field`.
|
10
|
+
#
|
11
|
+
# @since 0.2.0
|
12
|
+
# @api private
|
6
13
|
class Values
|
14
|
+
# @since 0.2.0
|
15
|
+
# @api private
|
7
16
|
GET_SEPARATOR = '.'.freeze
|
8
17
|
|
18
|
+
# @since 0.2.0
|
19
|
+
# @api private
|
9
20
|
def initialize(values, params)
|
10
21
|
@values = Utils::Hash.new(values).stringify!
|
11
22
|
@params = params
|
12
23
|
end
|
13
24
|
|
25
|
+
# Returns the value for the given key, if present
|
26
|
+
#
|
27
|
+
# @since 0.2.0
|
28
|
+
# @api private
|
14
29
|
def get(key)
|
15
30
|
@params.get(key) || _get_from_values(key)
|
16
31
|
end
|
17
32
|
|
18
33
|
private
|
34
|
+
|
35
|
+
# @since 0.2.0
|
36
|
+
# @api private
|
19
37
|
def _get_from_values(key)
|
20
38
|
initial_key, *keys = key.to_s.split(GET_SEPARATOR)
|
21
39
|
result = @values[initial_key]
|
@@ -23,11 +41,9 @@ module Hanami
|
|
23
41
|
Array(keys).each do |k|
|
24
42
|
break if result.nil?
|
25
43
|
|
26
|
-
result = if result.respond_to?(k)
|
27
|
-
|
28
|
-
|
29
|
-
nil
|
30
|
-
end
|
44
|
+
result = if result.respond_to?(k) # rubocop:disable Style/IfUnlessModifier
|
45
|
+
result.public_send(k)
|
46
|
+
end
|
31
47
|
end
|
32
48
|
|
33
49
|
result
|
@@ -12,15 +12,54 @@ module Hanami
|
|
12
12
|
# @api private
|
13
13
|
#
|
14
14
|
# @see http://www.w3.org/html/wg/drafts/html/master/infrastructure.html#boolean-attribute
|
15
|
-
BOOLEAN_ATTRIBUTES = %w
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
BOOLEAN_ATTRIBUTES = %w(
|
16
|
+
allowfullscreen
|
17
|
+
async
|
18
|
+
autobuffer
|
19
|
+
autofocus
|
20
|
+
autoplay
|
21
|
+
checked
|
22
|
+
compact
|
23
|
+
controls
|
24
|
+
declare
|
25
|
+
default
|
26
|
+
defaultchecked
|
27
|
+
defaultmuted
|
28
|
+
defaultselected
|
29
|
+
defer
|
30
|
+
disabled
|
31
|
+
draggable
|
32
|
+
enabled
|
33
|
+
formnovalidate
|
34
|
+
hidden
|
35
|
+
indeterminate
|
36
|
+
inert
|
37
|
+
ismap
|
38
|
+
itemscope
|
39
|
+
loop
|
40
|
+
multiple
|
41
|
+
muted
|
42
|
+
nohref
|
43
|
+
noresize
|
44
|
+
noshade
|
45
|
+
novalidate
|
46
|
+
nowrap
|
47
|
+
open
|
48
|
+
pauseonexit
|
49
|
+
pubdate
|
50
|
+
readonly
|
51
|
+
required
|
52
|
+
reversed
|
53
|
+
scoped
|
54
|
+
seamless
|
55
|
+
selected
|
56
|
+
sortable
|
57
|
+
spellcheck
|
58
|
+
translate
|
59
|
+
truespeed
|
60
|
+
typemustmatch
|
22
61
|
visible
|
23
|
-
|
62
|
+
).freeze
|
24
63
|
|
25
64
|
# Attributes separator
|
26
65
|
#
|
@@ -49,10 +88,11 @@ module Hanami
|
|
49
88
|
# @since 0.1.0
|
50
89
|
# @api private
|
51
90
|
def to_s
|
52
|
-
%(<#{
|
91
|
+
%(<#{@name}#{attributes}>)
|
53
92
|
end
|
54
93
|
|
55
94
|
private
|
95
|
+
|
56
96
|
# Resolve the attributes
|
57
97
|
#
|
58
98
|
# @return [String,NilClass] the tag attributes
|
@@ -60,7 +100,7 @@ module Hanami
|
|
60
100
|
# @since 0.1.0
|
61
101
|
# @api private
|
62
102
|
def attributes
|
63
|
-
return
|
103
|
+
return unless defined?(@attributes) && !@attributes.nil?
|
64
104
|
result = ''
|
65
105
|
|
66
106
|
@attributes.each do |attribute_name, value|
|
@@ -79,12 +119,12 @@ module Hanami
|
|
79
119
|
end
|
80
120
|
|
81
121
|
# Do not render boolean attributes when their value is _false_.
|
82
|
-
def boolean_attribute(attribute_name,
|
83
|
-
%(#{ATTRIBUTES_SEPARATOR}#{
|
122
|
+
def boolean_attribute(attribute_name, _value)
|
123
|
+
%(#{ATTRIBUTES_SEPARATOR}#{attribute_name}="#{attribute_name}")
|
84
124
|
end
|
85
125
|
|
86
126
|
def attribute(attribute_name, value)
|
87
|
-
%(#{ATTRIBUTES_SEPARATOR}#{
|
127
|
+
%(#{ATTRIBUTES_SEPARATOR}#{attribute_name}="#{value}")
|
88
128
|
end
|
89
129
|
end
|
90
130
|
end
|
@@ -12,7 +12,7 @@ module Hanami
|
|
12
12
|
# HTML Builder
|
13
13
|
#
|
14
14
|
# @since 0.1.0
|
15
|
-
class HtmlBuilder
|
15
|
+
class HtmlBuilder # rubocop:disable Metrics/ClassLength
|
16
16
|
# HTML5 content tags
|
17
17
|
#
|
18
18
|
# @since 0.1.0
|
@@ -20,103 +20,103 @@ module Hanami
|
|
20
20
|
#
|
21
21
|
# @see Hanami::Helpers::HtmlHelper::HtmlNode
|
22
22
|
# @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element
|
23
|
-
CONTENT_TAGS =
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
23
|
+
CONTENT_TAGS = %w(
|
24
|
+
a
|
25
|
+
abbr
|
26
|
+
address
|
27
|
+
article
|
28
|
+
aside
|
29
|
+
audio
|
30
|
+
b
|
31
|
+
bdi
|
32
|
+
bdo
|
33
|
+
blockquote
|
34
|
+
body
|
35
|
+
button
|
36
|
+
canvas
|
37
|
+
caption
|
38
|
+
cite
|
39
|
+
code
|
40
|
+
colgroup
|
41
|
+
data
|
42
|
+
datalist
|
43
|
+
del
|
44
|
+
details
|
45
|
+
dfn
|
46
|
+
div
|
47
|
+
dl
|
48
|
+
dt
|
49
|
+
dd
|
50
|
+
em
|
51
|
+
fieldset
|
52
|
+
figcaption
|
53
|
+
figure
|
54
|
+
footer
|
55
|
+
form
|
56
|
+
h1
|
57
|
+
h2
|
58
|
+
h3
|
59
|
+
h4
|
60
|
+
h5
|
61
|
+
h6
|
62
|
+
head
|
63
|
+
header
|
64
|
+
i
|
65
|
+
iframe
|
66
|
+
ins
|
67
|
+
kbd
|
68
|
+
label
|
69
|
+
legend
|
70
|
+
li
|
71
|
+
link
|
72
|
+
main
|
73
|
+
map
|
74
|
+
mark
|
75
|
+
math
|
76
|
+
menu
|
77
|
+
meter
|
78
|
+
nav
|
79
|
+
noscript
|
80
|
+
object
|
81
|
+
ol
|
82
|
+
optgroup
|
83
|
+
option
|
84
|
+
output
|
85
|
+
p
|
86
|
+
pre
|
87
|
+
progress
|
88
|
+
q
|
89
|
+
rp
|
90
|
+
rt
|
91
|
+
ruby
|
92
|
+
s
|
93
|
+
samp
|
94
|
+
script
|
95
|
+
section
|
96
|
+
select
|
97
|
+
small
|
98
|
+
span
|
99
|
+
strong
|
100
|
+
style
|
101
|
+
sub
|
102
|
+
summary
|
103
|
+
sup
|
104
|
+
svg
|
105
|
+
table
|
106
|
+
tbody
|
107
|
+
td
|
108
|
+
template
|
109
|
+
textarea
|
110
|
+
tfoot
|
111
|
+
th
|
112
|
+
thead
|
113
|
+
time
|
114
|
+
title
|
115
|
+
tr
|
116
|
+
u
|
117
|
+
ul
|
118
|
+
video
|
119
|
+
).freeze
|
120
120
|
|
121
121
|
# HTML5 empty tags
|
122
122
|
#
|
@@ -125,24 +125,24 @@ module Hanami
|
|
125
125
|
#
|
126
126
|
# @see Hanami::Helpers::HtmlHelper::EmptyHtmlNode
|
127
127
|
# @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element
|
128
|
-
EMPTY_TAGS =
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
128
|
+
EMPTY_TAGS = %w(
|
129
|
+
area
|
130
|
+
base
|
131
|
+
br
|
132
|
+
col
|
133
|
+
embed
|
134
|
+
hr
|
135
|
+
img
|
136
|
+
input
|
137
|
+
keygen
|
138
|
+
link
|
139
|
+
menuitem
|
140
|
+
meta
|
141
|
+
param
|
142
|
+
source
|
143
|
+
track
|
144
|
+
wbr
|
145
|
+
).freeze
|
146
146
|
|
147
147
|
# New line separator
|
148
148
|
#
|
@@ -152,8 +152,8 @@ module Hanami
|
|
152
152
|
|
153
153
|
CONTENT_TAGS.each do |tag|
|
154
154
|
class_eval %{
|
155
|
-
def #{
|
156
|
-
@nodes << self.class.html_node.new(:#{
|
155
|
+
def #{tag}(content = nil, attributes = nil, &blk)
|
156
|
+
@nodes << self.class.html_node.new(:#{tag}, blk || content, attributes || content, options)
|
157
157
|
self
|
158
158
|
end
|
159
159
|
}
|
@@ -161,8 +161,8 @@ module Hanami
|
|
161
161
|
|
162
162
|
EMPTY_TAGS.each do |tag|
|
163
163
|
class_eval %{
|
164
|
-
def #{
|
165
|
-
@nodes << EmptyHtmlNode.new(:#{
|
164
|
+
def #{tag}(attributes = nil)
|
165
|
+
@nodes << EmptyHtmlNode.new(:#{tag}, attributes)
|
166
166
|
self
|
167
167
|
end
|
168
168
|
}
|
@@ -310,7 +310,7 @@ module Hanami
|
|
310
310
|
|
311
311
|
# @since 0.2.5
|
312
312
|
# @api private
|
313
|
-
|
313
|
+
alias + text
|
314
314
|
|
315
315
|
# Resolves all the nodes and generates the markup
|
316
316
|
#
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'hanami/utils/escape'
|
2
|
+
|
1
3
|
module Hanami
|
2
4
|
module Helpers
|
3
5
|
module HtmlHelper
|
@@ -36,7 +38,7 @@ module Hanami
|
|
36
38
|
if @builder.nested?
|
37
39
|
@builder.to_s
|
38
40
|
else
|
39
|
-
|
41
|
+
Utils::Escape.html(result)
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'hanami/helpers/html_helper/empty_html_node'
|
2
|
+
require 'hanami/utils/escape'
|
2
3
|
|
3
4
|
module Hanami
|
4
5
|
module Helpers
|
@@ -15,10 +16,10 @@ module Hanami
|
|
15
16
|
# @param name [Symbol,String] the name of the tag
|
16
17
|
# @param content [String,Proc,Hanami::Helpers::HtmlHelper::HtmlBuilder,NilClass] the optional content
|
17
18
|
# @param attributes [Hash,NilClass] the optional tag attributes
|
18
|
-
# @param
|
19
|
+
# @param _options [Hash] a optional set of data
|
19
20
|
#
|
20
21
|
# @return [Hanami::Helpers::HtmlHelper::HtmlNode]
|
21
|
-
def initialize(name, content, attributes,
|
22
|
+
def initialize(name, content, attributes, _options = {})
|
22
23
|
@builder = HtmlBuilder.new
|
23
24
|
@name = name
|
24
25
|
@content = case content
|
@@ -40,25 +41,26 @@ module Hanami
|
|
40
41
|
#
|
41
42
|
# @see Hanami::Helpers::HtmlHelper::EmptyHtmlNode#to_s
|
42
43
|
def to_s
|
43
|
-
%(#{
|
44
|
+
%(#{super}#{content}</#{@name}>)
|
44
45
|
end
|
45
46
|
|
46
47
|
private
|
48
|
+
|
47
49
|
# Resolve the (nested) content
|
48
50
|
#
|
49
51
|
# @return [String] the content
|
50
52
|
#
|
51
53
|
# @since 0.1.0
|
52
54
|
# @api private
|
53
|
-
def content
|
55
|
+
def content # rubocop:disable Metrics/MethodLength
|
54
56
|
case @content
|
55
57
|
when Proc
|
56
58
|
result = @builder.resolve(&@content)
|
57
59
|
|
58
60
|
if @builder.nested?
|
59
|
-
"\n#{
|
61
|
+
"\n#{@builder}\n"
|
60
62
|
else
|
61
|
-
"\n#{
|
63
|
+
"\n#{Utils::Escape.html(result)}\n"
|
62
64
|
end
|
63
65
|
else
|
64
66
|
Utils::Escape.html(@content)
|
@@ -115,7 +115,7 @@ module Hanami
|
|
115
115
|
# @example With only content
|
116
116
|
# <%= link_to 'Home' %>
|
117
117
|
# # => ArgumentError
|
118
|
-
def link_to(content, url = nil, options = {}, &blk)
|
118
|
+
def link_to(content, url = nil, options = {}, &blk) # rubocop:disable Metrics/MethodLength
|
119
119
|
if block_given?
|
120
120
|
options = url || {}
|
121
121
|
url = content
|
@@ -128,7 +128,7 @@ module Hanami
|
|
128
128
|
raise ArgumentError
|
129
129
|
end
|
130
130
|
|
131
|
-
html.a(blk || content, options)
|
131
|
+
html.a(blk || content, options)
|
132
132
|
end
|
133
133
|
end
|
134
134
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'hanami/utils/kernel'
|
2
|
+
|
1
3
|
module Hanami
|
2
4
|
module Helpers
|
3
5
|
# Number formatter
|
@@ -11,6 +13,7 @@ module Hanami
|
|
11
13
|
# @since 0.2.0
|
12
14
|
module NumberFormattingHelper
|
13
15
|
private
|
16
|
+
|
14
17
|
# Format the given number, according to the options
|
15
18
|
#
|
16
19
|
# It accepts a number (<tt>Numeric</tt>) or a string representation.
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'hanami/utils/string'
|
2
|
+
|
1
3
|
module Hanami
|
2
4
|
module Helpers
|
3
5
|
# Routing helper for full stack Hanami web applications.
|
@@ -39,11 +41,11 @@ module Hanami
|
|
39
41
|
# # <%= link_to_home %>
|
40
42
|
module RoutingHelper
|
41
43
|
def self.included(base)
|
42
|
-
factory = "#{
|
44
|
+
factory = "#{Utils::String.new(base).namespace}::Routes"
|
43
45
|
|
44
46
|
base.class_eval <<-END_EVAL, __FILE__, __LINE__
|
45
47
|
def routes
|
46
|
-
#{
|
48
|
+
#{factory}
|
47
49
|
end
|
48
50
|
END_EVAL
|
49
51
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hanami-helpers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2016-
|
13
|
+
date: 2016-07-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: hanami-utils
|
@@ -18,14 +18,14 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '0.
|
21
|
+
version: '0.8'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
26
|
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '0.
|
28
|
+
version: '0.8'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: bundler
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -46,14 +46,14 @@ dependencies:
|
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version: '
|
49
|
+
version: '11'
|
50
50
|
type: :development
|
51
51
|
prerelease: false
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
54
|
- - "~>"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version: '
|
56
|
+
version: '11'
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
58
|
name: minitest
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
@@ -110,7 +110,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
110
|
requirements:
|
111
111
|
- - ">="
|
112
112
|
- !ruby/object:Gem::Version
|
113
|
-
version: 2.
|
113
|
+
version: 2.2.0
|
114
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
115
|
requirements:
|
116
116
|
- - ">="
|
@@ -118,9 +118,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
118
118
|
version: '0'
|
119
119
|
requirements: []
|
120
120
|
rubyforge_project:
|
121
|
-
rubygems_version: 2.
|
121
|
+
rubygems_version: 2.6.4
|
122
122
|
signing_key:
|
123
123
|
specification_version: 4
|
124
124
|
summary: Hanami helpers
|
125
125
|
test_files: []
|
126
|
-
has_rdoc:
|