bh 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -1
  3. data/CHANGELOG.md +19 -0
  4. data/README.md +51 -18
  5. data/bh.gemspec +13 -9
  6. data/examples/middleman/.gitignore +18 -0
  7. data/examples/middleman/Gemfile +6 -0
  8. data/examples/middleman/config.rb +1 -0
  9. data/examples/middleman/source/index.html.erb +158 -0
  10. data/examples/padrino/Gemfile +9 -0
  11. data/examples/padrino/app/app.rb +16 -0
  12. data/examples/padrino/app/views/index.html.erb +155 -0
  13. data/examples/padrino/config.ru +5 -0
  14. data/examples/padrino/config/apps.rb +5 -0
  15. data/examples/padrino/config/boot.rb +8 -0
  16. data/examples/rails/.gitignore +12 -0
  17. data/examples/rails/Gemfile +5 -0
  18. data/examples/rails/app/controllers/application_controller.rb +6 -0
  19. data/examples/rails/app/controllers/users_controller.rb +2 -0
  20. data/examples/rails/app/models/user.rb +15 -0
  21. data/examples/rails/app/views/application/index.html.erb +160 -0
  22. data/examples/rails/bin/rails +4 -0
  23. data/examples/rails/config.ru +4 -0
  24. data/examples/rails/config/application.rb +12 -0
  25. data/examples/rails/config/boot.rb +3 -0
  26. data/examples/rails/config/environment.rb +5 -0
  27. data/examples/rails/config/environments/development.rb +7 -0
  28. data/examples/rails/config/routes.rb +4 -0
  29. data/examples/rails/config/secrets.yml +22 -0
  30. data/examples/rails/log/.keep +0 -0
  31. data/gemfiles/Gemfile.rails-3.x +2 -0
  32. data/gemfiles/Gemfile.rails-4.x +2 -0
  33. data/lib/bh.rb +15 -4
  34. data/lib/bh/classes/alert_box.rb +35 -0
  35. data/lib/bh/classes/base.rb +125 -0
  36. data/lib/bh/classes/button.rb +58 -0
  37. data/lib/bh/classes/button_to.rb +33 -0
  38. data/lib/bh/classes/cdn.rb +35 -0
  39. data/lib/bh/classes/dropdown.rb +56 -0
  40. data/lib/bh/classes/icon.rb +34 -0
  41. data/lib/bh/classes/link_to.rb +22 -0
  42. data/lib/bh/classes/modal.rb +68 -0
  43. data/lib/bh/classes/nav.rb +37 -0
  44. data/lib/bh/classes/navbar.rb +78 -0
  45. data/lib/bh/classes/panel.rb +72 -0
  46. data/lib/bh/classes/panel_row.rb +13 -0
  47. data/lib/bh/classes/progress_bar.rb +89 -0
  48. data/lib/bh/classes/stack.rb +19 -0
  49. data/lib/bh/classes/vertical.rb +27 -0
  50. data/lib/bh/core_ext/middleman.rb +24 -0
  51. data/lib/bh/core_ext/padrino.rb +25 -0
  52. data/lib/bh/core_ext/rails/base_helper.rb +21 -0
  53. data/lib/bh/{helpers → core_ext/rails}/form/base_helper.rb +3 -1
  54. data/lib/bh/{helpers → core_ext/rails}/form/check_box_helper.rb +1 -1
  55. data/lib/bh/{helpers → core_ext/rails}/form/field_helper.rb +1 -1
  56. data/lib/bh/{helpers → core_ext/rails}/form/fields_for_helper.rb +1 -1
  57. data/lib/bh/{helpers → core_ext/rails}/form/fieldset_helper.rb +1 -1
  58. data/lib/bh/{helpers → core_ext/rails}/form/file_field_helper.rb +1 -1
  59. data/lib/bh/{helpers → core_ext/rails}/form/legend_helper.rb +1 -1
  60. data/lib/bh/{helpers → core_ext/rails}/form/radio_button_helper.rb +1 -1
  61. data/lib/bh/{helpers → core_ext/rails}/form/select_helper.rb +1 -1
  62. data/lib/bh/{helpers → core_ext/rails}/form/static_control_helper.rb +1 -1
  63. data/lib/bh/{helpers → core_ext/rails}/form/submit_helper.rb +1 -1
  64. data/lib/bh/{form_builders → core_ext/rails}/form_builder.rb +11 -10
  65. data/lib/bh/core_ext/rails/form_for_helper.rb +32 -0
  66. data/lib/bh/core_ext/railtie.rb +27 -0
  67. data/lib/bh/helpers/alert_box_helper.rb +40 -0
  68. data/lib/bh/helpers/button_helper.rb +35 -58
  69. data/lib/bh/helpers/button_to_helper.rb +48 -10
  70. data/lib/bh/helpers/cdn_helper.rb +11 -35
  71. data/lib/bh/helpers/dropdown_helper.rb +29 -62
  72. data/lib/bh/helpers/glyphicon_helper.rb +7 -13
  73. data/lib/bh/helpers/horizontal_helper.rb +35 -0
  74. data/lib/bh/helpers/icon_helper.rb +15 -29
  75. data/lib/bh/helpers/link_to_helper.rb +52 -41
  76. data/lib/bh/helpers/modal_helper.rb +49 -79
  77. data/lib/bh/helpers/nav_helper.rb +25 -40
  78. data/lib/bh/helpers/navbar_helper.rb +36 -170
  79. data/lib/bh/helpers/panel_helper.rb +45 -72
  80. data/lib/bh/helpers/panel_row_helper.rb +20 -38
  81. data/lib/bh/helpers/progress_bar_helper.rb +48 -59
  82. data/lib/bh/helpers/vertical_helper.rb +33 -0
  83. data/lib/bh/version.rb +1 -1
  84. data/lib/bh/views/bh/_alert_dismiss_button.html +4 -0
  85. data/lib/bh/views/bh/_dropdown.html.erb +5 -5
  86. data/lib/bh/views/bh/_dropdown_split.html.erb +5 -5
  87. data/lib/bh/views/bh/_modal.html.erb +5 -8
  88. data/lib/bh/views/bh/_navbar.html.erb +5 -0
  89. data/spec/padrino/button_to_helper.rb +35 -0
  90. data/spec/padrino_spec.rb +28 -0
  91. data/spec/rails/button_to_helper.rb +31 -0
  92. data/spec/{helpers → rails}/form/check_box_helper_spec.rb +3 -3
  93. data/spec/{helpers → rails}/form/field_helper_spec.rb +3 -3
  94. data/spec/{helpers → rails}/form/fields_for_helper_spec.rb +3 -3
  95. data/spec/{helpers → rails}/form/fieldset_helper_spec.rb +3 -3
  96. data/spec/{helpers → rails}/form/file_field_helper_spec.rb +3 -3
  97. data/spec/{helpers → rails}/form/legend_helper_spec.rb +3 -3
  98. data/spec/{helpers → rails}/form/radio_button_helper_spec.rb +3 -3
  99. data/spec/{helpers → rails}/form/select_helper_spec.rb +3 -3
  100. data/spec/{helpers → rails}/form/static_control_helper_spec.rb +3 -3
  101. data/spec/{helpers → rails}/form/submit_helper_spec.rb +3 -3
  102. data/spec/{helpers → rails}/form_for_helper_spec.rb +3 -3
  103. data/spec/rails_helper.rb +25 -0
  104. data/spec/rails_spec.rb +28 -0
  105. data/spec/shared/alert_box_helper.rb +62 -0
  106. data/spec/shared/button_helper.rb +52 -0
  107. data/spec/shared/button_to_helper.rb +42 -0
  108. data/spec/shared/cdn_helper.rb +36 -0
  109. data/spec/shared/dropdown_helper.rb +112 -0
  110. data/spec/shared/glyphicon_helper.rb +21 -0
  111. data/spec/shared/horizontal_helper.rb +37 -0
  112. data/spec/shared/icon_helper.rb +31 -0
  113. data/spec/shared/link_to_helper.rb +62 -0
  114. data/spec/shared/modal_helper.rb +104 -0
  115. data/spec/shared/nav_helper.rb +49 -0
  116. data/spec/shared/navbar_helper.rb +63 -0
  117. data/spec/shared/panel_helper.rb +76 -0
  118. data/spec/shared/panel_row_helper.rb +21 -0
  119. data/spec/shared/progress_bar_helper.rb +103 -0
  120. data/spec/shared/vertical_helper.rb +43 -0
  121. data/spec/spec_helper.rb +6 -29
  122. data/spec/support/matchers.rb +38 -0
  123. data/spec/support/padrino.rb +33 -0
  124. data/spec/support/rails.rb +27 -0
  125. metadata +183 -94
  126. data/config.rb +0 -6
  127. data/lib/bh/helpers/alert_helper.rb +0 -77
  128. data/lib/bh/helpers/base_helper.rb +0 -39
  129. data/lib/bh/helpers/form_for_helper.rb +0 -30
  130. data/lib/bh/middleman.rb +0 -39
  131. data/lib/bh/railtie.rb +0 -42
  132. data/spec/dummy/index.html.erb +0 -60
  133. data/spec/dummy/layouts/default.erb +0 -17
  134. data/spec/helpers/alert_helper_spec.rb +0 -84
  135. data/spec/helpers/button_helper_spec.rb +0 -100
  136. data/spec/helpers/button_to_helper_spec.rb +0 -25
  137. data/spec/helpers/cdn_helper_spec.rb +0 -100
  138. data/spec/helpers/dropdown_helper_spec.rb +0 -146
  139. data/spec/helpers/glyphicon_helper_spec.rb +0 -21
  140. data/spec/helpers/icon_helper_spec.rb +0 -45
  141. data/spec/helpers/link_to_helper_spec.rb +0 -124
  142. data/spec/helpers/modal_helper_spec.rb +0 -133
  143. data/spec/helpers/nav_helper_spec.rb +0 -53
  144. data/spec/helpers/navbar_helper_spec.rb +0 -194
  145. data/spec/helpers/panel_helper_spec.rb +0 -95
  146. data/spec/helpers/panel_row_helper_spec.rb +0 -27
  147. data/spec/helpers/progress_bar_helper_spec.rb +0 -114
@@ -0,0 +1,58 @@
1
+ require 'bh/classes/base'
2
+
3
+ module Bh
4
+ module Classes
5
+ class Button < Base
6
+ # @return [#to_s] the context-related class to assign to the button.
7
+ def context_class
8
+ Button.contexts[@options[:context]]
9
+ end
10
+
11
+ # @return [#to_s] the size-related class to assign to the alert box.
12
+ def size_class
13
+ Button.sizes[@options[:size]]
14
+ end
15
+
16
+ # @return [#to_s] the layout-related class to assign to the alert box.
17
+ def layout_class
18
+ Button.layouts[@options[:layout]]
19
+ end
20
+
21
+ private
22
+
23
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
24
+ # append to buttons for each possible context.
25
+ def self.contexts
26
+ HashWithIndifferentAccess.new(:'btn-default').tap do |klass|
27
+ klass[:danger] = :'btn-danger'
28
+ klass[:info] = :'btn-info'
29
+ klass[:link] = :'btn-link'
30
+ klass[:primary] = :'btn-primary'
31
+ klass[:success] = :'btn-success'
32
+ klass[:warning] = :'btn-warning'
33
+ end
34
+ end
35
+
36
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
37
+ # append to buttons for each possible size.
38
+ def self.sizes
39
+ HashWithIndifferentAccess.new.tap do |klass|
40
+ klass[:extra_small] = :'btn-xs'
41
+ klass[:large] = :'btn-lg'
42
+ klass[:lg] = :'btn-lg'
43
+ klass[:sm] = :'btn-sm'
44
+ klass[:small] = :'btn-sm'
45
+ klass[:xs] = :'btn-xs'
46
+ end
47
+ end
48
+
49
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
50
+ # append to buttons for each possible layout.
51
+ def self.layouts
52
+ HashWithIndifferentAccess.new.tap do |klass|
53
+ klass[:block] = :'btn-block'
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,33 @@
1
+ require 'bh/classes/button'
2
+
3
+ module Bh
4
+ module Classes
5
+ class ButtonTo < Button
6
+ def initialize(app = nil, *args, &block)
7
+ @url = extract_url_from(*args, &block)
8
+ super
9
+ end
10
+
11
+ def append_button_class!(klass)
12
+ case Bh.framework
13
+ when :rails then append_class! klass
14
+ when :padrino, :middleman then append_class_to! :submit_options, klass
15
+ end
16
+ end
17
+
18
+ def append_form_class!(klass)
19
+ case Bh.framework
20
+ when :rails then append_class! klass, html_attributes, :form_class
21
+ when :padrino, :middleman then append_class! klass
22
+ end
23
+ end
24
+
25
+ def accepts_block?
26
+ case Bh.framework
27
+ when :rails then defined?(ActionView::VERSION) # only Rails >= 4
28
+ when :padrino, :middleman then true
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,35 @@
1
+ require 'bh/classes/base'
2
+
3
+ module Bh
4
+ module Classes
5
+ # @api private
6
+ class Cdn
7
+ # @note if unspecified, the version should match the latest available
8
+ # version. If that's not the case, it's a bug and should be fixed.
9
+ def self.bootstrap(options = {})
10
+ options[:version] ||= '3.3.0'
11
+ cdn_asset options.merge(library: 'bootstrap')
12
+ end
13
+
14
+ # @note if unspecified, the version should match the latest available
15
+ # version. If that's not the case, it's a bug and should be fixed.
16
+ def self.font_awesome(options = {})
17
+ options[:version] ||= '4.2.0'
18
+ cdn_asset options.merge(library: 'font-awesome')
19
+ end
20
+
21
+ private
22
+
23
+ def self.cdn_asset(options = {})
24
+ version = options[:version]
25
+ extension = options[:extension]
26
+ name = options[:name]
27
+ name = "#{name}.min" if options.fetch(:minified, true)
28
+ library = options[:library]
29
+ scheme = "#{options[:scheme]}:" if options[:scheme]
30
+ host = "#{scheme}//netdna.bootstrapcdn.com"
31
+ "#{host}/#{library}/#{version}/#{extension}/#{name}.#{extension}"
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,56 @@
1
+ require 'bh/classes/button'
2
+
3
+ module Bh
4
+ module Classes
5
+ class Dropdown < Button
6
+ # @return [#to_s] the group-related class to assign to the dropdown.
7
+ def groupable_class
8
+ Dropdown.groupables[@options[:groupable]]
9
+ end
10
+
11
+ # @return [#to_s] the direction-related class to assign to the dropdown.
12
+ def direction_class
13
+ Dropdown.directions[@options[:direction]]
14
+ end
15
+
16
+ # @return [#to_s] the align-related class to assign to the dropdown.
17
+ def align_class
18
+ Dropdown.aligns[@options[:align]]
19
+ end
20
+
21
+ def id
22
+ @options.fetch :id, "dropdown-#{rand 10**10}"
23
+ end
24
+
25
+ def partial
26
+ @options[:split] ? 'dropdown_split' : 'dropdown'
27
+ end
28
+
29
+ private
30
+
31
+ # @return [Hash<Symbol, String>] the class that Bootstrap requires to
32
+ # append to a dropdown to display it as inline or block.
33
+ def self.groupables
34
+ HashWithIndifferentAccess.new(:'btn-group').tap do |klass|
35
+ klass[false] = :dropdown
36
+ end
37
+ end
38
+
39
+ # @return [Hash<Symbol, String>] the class that Bootstrap requires to
40
+ # append to a dropdown to show a drop-"up" or -"down".
41
+ def self.directions
42
+ HashWithIndifferentAccess.new.tap do |klass|
43
+ klass[:up] = :dropup
44
+ end
45
+ end
46
+
47
+ # @return [Hash<Symbol, String>] the class that Bootstrap requires to
48
+ # append to a dropdown to left- or right- align to the toggle button.
49
+ def self.aligns
50
+ HashWithIndifferentAccess.new.tap do |klass|
51
+ klass[:right] = :'dropdown-menu-right'
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,34 @@
1
+ require 'bh/classes/base'
2
+
3
+ module Bh
4
+ module Classes
5
+ # @api private
6
+ class Icon < Base
7
+ # @return [#to_s] the class to assign to the icon based on the Vector
8
+ # Icon library used.
9
+ def library_class
10
+ Icon.libraries[@options[:library].to_s.underscore] || @options[:library]
11
+ end
12
+
13
+ # @return [#to_s] the class to assign to the icon based on the name
14
+ # of the icon.
15
+ def name_class
16
+ if name = @options[:name]
17
+ "#{library_class}-#{name.to_s.gsub '_', '-'}"
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
24
+ # append to icons for each possible vector icon library.
25
+ def self.libraries
26
+ HashWithIndifferentAccess.new(nil).tap do |klass|
27
+ klass[:font_awesome] = :'fa'
28
+ klass[:glyphicons] = :'glyphicon'
29
+ klass[:''] = :'glyphicon'
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,22 @@
1
+ require 'bh/classes/base'
2
+
3
+ module Bh
4
+ module Classes
5
+ class LinkTo < Base
6
+ def initialize(app = nil, *args, &block)
7
+ @url = extract_url_from(*args, &block)
8
+ super
9
+ end
10
+
11
+ def current_page?
12
+ case Bh.framework
13
+ when :rails
14
+ @app.current_page? @url
15
+ when :padrino, :middleman
16
+ request = Bh.framework == :middleman ? @app.req : @app.request
17
+ request.path_info == @app.url_for(@url)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,68 @@
1
+ require 'bh/classes/button'
2
+
3
+ module Bh
4
+ module Classes
5
+ class Modal < Base
6
+ # Differently from other classes, Modal works with no content or block,
7
+ # given that the options[:body] is passed, in which case it functions
8
+ # as the content.
9
+ def initialize(app = nil, *args, &block)
10
+ if args.first.is_a?(Hash) && !block_given?
11
+ args.unshift args.first.delete(:body)
12
+ end
13
+
14
+ super
15
+ end
16
+
17
+ # @return [#to_s] the context-related class to assign to the modal button.
18
+ def button_context_class
19
+ Button.contexts[@options.fetch(:button, {})[:context]]
20
+ end
21
+
22
+ # @return [#to_s] the size-related class to assign to the modal button.
23
+ def button_size_class
24
+ Button.sizes[@options.fetch(:button, {})[:size]]
25
+ end
26
+
27
+ # @return [#to_s] the size-related class to assign to the modal dialog.
28
+ def dialog_size_class
29
+ Modal.dialog_sizes[@options[:size]]
30
+ end
31
+
32
+ # @return [#to_s] the caption for the modal button.
33
+ def caption
34
+ @options.fetch(:button, {}).fetch :caption, title
35
+ end
36
+
37
+ # @return [#to_s] the title to display on top of the modal dialog.
38
+ def title
39
+ @options.fetch :title, 'Modal'
40
+ end
41
+
42
+ def id
43
+ @options.fetch :id, "modal-#{rand 10**10}"
44
+ end
45
+
46
+ private
47
+
48
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
49
+ # append to the modal dialog for each possible size.
50
+ def self.dialog_sizes
51
+ HashWithIndifferentAccess.new.tap do |klass|
52
+ klass[:large] = :'modal-lg'
53
+ klass[:lg] = :'modal-lg'
54
+ klass[:sm] = :'modal-sm'
55
+ klass[:small] = :'modal-sm'
56
+ end
57
+ end
58
+
59
+ def extract_content_from(*args, &block)
60
+ if block_given?
61
+ super
62
+ else
63
+ @app.content_tag :div, super, class: 'modal-body'
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,37 @@
1
+ require 'bh/classes/base'
2
+
3
+ module Bh
4
+ module Classes
5
+ # @api private
6
+ class Nav < Base
7
+ # @return [#to_s] the style-related class to assign to the nav.
8
+ def style_class
9
+ Nav.styles[@options[:as]]
10
+ end
11
+
12
+ # @return [#to_s] the layout-related class to assign to the nav.
13
+ def layout_class
14
+ Nav.layouts[@options[:layout]]
15
+ end
16
+
17
+ private
18
+
19
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
20
+ # append to navs for each possible style.
21
+ def self.styles
22
+ HashWithIndifferentAccess.new(:'nav-tabs').tap do |klass|
23
+ klass[:pills] = :'nav-pills'
24
+ end
25
+ end
26
+
27
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
28
+ # append to buttons for each possible layout.
29
+ def self.layouts
30
+ HashWithIndifferentAccess.new.tap do |klass|
31
+ klass[:justified] = :'nav-justified'
32
+ klass[:stacked] = :'nav-stacked'
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,78 @@
1
+ require 'bh/classes/base'
2
+
3
+ module Bh
4
+ module Classes
5
+ class Navbar < Base
6
+ # @return [#to_s] the style-related class to assign to the navbar.
7
+ def style_class
8
+ Navbar.styles[@options[:inverted]]
9
+ end
10
+
11
+ # @return [#to_s] the position-related class to assign to the navbar.
12
+ def position_class
13
+ Navbar.positions[@options[:position]]
14
+ end
15
+
16
+ # @return [#to_s] the layout-related class to assign to the navbar.
17
+ def layout_class
18
+ Navbar.layouts[@options[:fluid]]
19
+ end
20
+
21
+ def id
22
+ @id ||= @options.fetch :id, "navbar-collapse-#{rand 10**10}"
23
+ end
24
+
25
+ # @private
26
+ # The fixed navbar will overlay your other content, unless you add padding
27
+ # to the top or bottom of the <body>. Try out your own values or use our
28
+ # snippet below. Tip: By default, the navbar is 50px high.
29
+ # @see http://getbootstrap.com/components/#navbar-fixed-top
30
+ def body_padding_style
31
+ if body_padding_amount && body_padding_type
32
+ style = "padding-#{body_padding_type}: #{body_padding_amount}px"
33
+ @app.content_tag :style, "body {#{style}}"
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
40
+ # append to navbars to specify a color combination.
41
+ def self.styles
42
+ HashWithIndifferentAccess.new(:'navbar-default').tap do |klass|
43
+ klass[true] = :'navbar-inverse'
44
+ end
45
+ end
46
+
47
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
48
+ # append to navbars to set a specific DOM position.
49
+ def self.positions
50
+ HashWithIndifferentAccess.new.tap do |klass|
51
+ klass[:static] = :'navbar-static-top'
52
+ klass[:static_top] = :'navbar-static-top'
53
+ klass[:top] = :'navbar-fixed-top'
54
+ klass[:fixed_top] = :'navbar-fixed-top'
55
+ klass[:bottom] = :'navbar-fixed-bottom'
56
+ klass[:fixed_bottom] = :'navbar-fixed-bottom'
57
+ end
58
+ end
59
+
60
+ # @return [Hash<Symbol, String>] the classes that Bootstrap requires to
61
+ # append to the navbar container for each possible layout.
62
+ def self.layouts
63
+ HashWithIndifferentAccess.new(:'container').tap do |klass|
64
+ klass[true] = :'container-fluid'
65
+ end
66
+ end
67
+
68
+ def body_padding_amount
69
+ @options.fetch :padding, 70
70
+ end
71
+
72
+ def body_padding_type
73
+ /navbar-fixed-(?<type>top|bottom)$/ =~ position_class
74
+ type
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,72 @@
1
+ require 'bh/classes/base'
2
+
3
+ module Bh
4
+ module Classes
5
+ class Panel < Base
6
+ # Differently from other classes, Panel works with no content or block,
7
+ # given that the options[:body] is passed, in which case it functions
8
+ # as the content.
9
+ def initialize(app = nil, *args, &block)
10
+ if args.first.is_a?(Hash) && !block_given?
11
+ args.unshift args.first.delete(:body)
12
+ end
13
+
14
+ super
15
+ end
16
+
17
+ # @return [#to_s] the content-related class to assign to the panel.
18
+ def context_class
19
+ Panel.contexts[@options[:context]]
20
+ end
21
+
22
+ # @return [#to_s] the HTML tag to wrap the panel in.
23
+ def tag
24
+ @options.fetch :tag, :div
25
+ end
26
+
27
+ # @return [#to_s] the text to display as the panel header
28
+ def heading
29
+ text = title || @options[:heading]
30
+ @app.content_tag :div, text, class: 'panel-heading' if text
31
+ end
32
+
33
+ def merge_html!(html)
34
+ @content ||= html
35
+ end
36
+
37
+ def body
38
+ if @options[:body]
39
+ @app.content_tag :div, @options[:body], class: 'panel-body'
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ def extract_content_from(*args, &block)
46
+ if block_given?
47
+ super
48
+ else
49
+ @app.content_tag :div, super, class: 'panel-body'
50
+ end
51
+ end
52
+
53
+ def title
54
+ if @options[:title]
55
+ @app.content_tag :h3, @options[:title], class: 'panel-title'
56
+ end
57
+ end
58
+
59
+ # @return [Hash<Symbol, String>] the class that Bootstrap requires to
60
+ # append to an panel box based on its context.
61
+ def self.contexts
62
+ HashWithIndifferentAccess.new(:'panel-default').tap do |klass|
63
+ klass[:primary] = :'panel-primary'
64
+ klass[:success] = :'panel-success'
65
+ klass[:info] = :'panel-info'
66
+ klass[:warning] = :'panel-warning'
67
+ klass[:danger] = :'panel-danger'
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end