twitter-bootstrap-rails 5.3.0 → 5.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.
Files changed (194) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +81 -0
  3. data/README.md +128 -628
  4. data/app/assets/javascripts/twitter/bootstrap/bootstrap.min.js +3 -3
  5. data/app/assets/stylesheets/twitter-bootstrap-static/bootstrap.css +3 -3
  6. data/lib/generators/bootstrap/badge/badge_generator.rb +13 -0
  7. data/lib/generators/bootstrap/breadcrumb/breadcrumb_generator.rb +13 -0
  8. data/lib/generators/bootstrap/button/button_generator.rb +13 -0
  9. data/lib/generators/bootstrap/cdn/cdn_generator.rb +39 -0
  10. data/lib/generators/bootstrap/cdn_tags.rb +43 -0
  11. data/lib/generators/bootstrap/dropdown/dropdown_generator.rb +13 -0
  12. data/lib/generators/bootstrap/features/features_generator.rb +13 -0
  13. data/lib/generators/bootstrap/footer/footer_generator.rb +13 -0
  14. data/lib/generators/bootstrap/header/header_generator.rb +13 -0
  15. data/lib/generators/bootstrap/hero/hero_generator.rb +13 -0
  16. data/lib/generators/bootstrap/install/install_generator.rb +120 -61
  17. data/lib/generators/bootstrap/install/templates/application.js +1 -1
  18. data/lib/generators/bootstrap/install/templates/bootstrap.js +10 -3
  19. data/lib/generators/bootstrap/install/templates/bootstrap_and_overrides.css +2 -2
  20. data/lib/generators/bootstrap/jumbotron/jumbotron_generator.rb +13 -0
  21. data/lib/generators/bootstrap/layout/layout_generator.rb +65 -1
  22. data/lib/generators/bootstrap/layout/templates/layout.html.erb +14 -9
  23. data/lib/generators/bootstrap/layout/templates/layout.html.haml +28 -43
  24. data/lib/generators/bootstrap/layout/templates/layout.html.slim +25 -40
  25. data/lib/generators/bootstrap/list_group/list_group_generator.rb +13 -0
  26. data/lib/generators/bootstrap/modal/modal_generator.rb +13 -0
  27. data/lib/generators/bootstrap/sidebar/sidebar_generator.rb +13 -0
  28. data/lib/generators/bootstrap/snippets/snippet_base.rb +126 -0
  29. data/lib/generators/bootstrap/snippets/snippet_catalog.rb +134 -0
  30. data/lib/generators/bootstrap/snippets/templates/badges/pills.html.erb +10 -0
  31. data/lib/generators/bootstrap/snippets/templates/badges/subtle.html.erb +10 -0
  32. data/lib/generators/bootstrap/snippets/templates/badges/subtle_bordered.html.erb +20 -0
  33. data/lib/generators/bootstrap/snippets/templates/badges/with_avatar.html.erb +34 -0
  34. data/lib/generators/bootstrap/snippets/templates/badges/with_avatar_divider.html.erb +66 -0
  35. data/lib/generators/bootstrap/snippets/templates/badges/with_icons.html.erb +26 -0
  36. data/lib/generators/bootstrap/snippets/templates/breadcrumbs/basic.html.erb +9 -0
  37. data/lib/generators/bootstrap/snippets/templates/breadcrumbs/chevron.html.erb +18 -0
  38. data/lib/generators/bootstrap/snippets/templates/breadcrumbs/custom.html.erb +18 -0
  39. data/lib/generators/bootstrap/snippets/templates/breadcrumbs/with_icons.html.erb +18 -0
  40. data/lib/generators/bootstrap/snippets/templates/buttons/circle.html.erb +20 -0
  41. data/lib/generators/bootstrap/snippets/templates/buttons/grid.html.erb +6 -0
  42. data/lib/generators/bootstrap/snippets/templates/buttons/loading.html.erb +10 -0
  43. data/lib/generators/bootstrap/snippets/templates/buttons/pills.html.erb +11 -0
  44. data/lib/generators/bootstrap/snippets/templates/buttons/with_icons.html.erb +14 -0
  45. data/lib/generators/bootstrap/snippets/templates/dropdowns/calendar.html.erb +156 -0
  46. data/lib/generators/bootstrap/snippets/templates/dropdowns/mega_menu.html.erb +140 -0
  47. data/lib/generators/bootstrap/snippets/templates/dropdowns/simple.html.erb +20 -0
  48. data/lib/generators/bootstrap/snippets/templates/dropdowns/with_icons.html.erb +88 -0
  49. data/lib/generators/bootstrap/snippets/templates/dropdowns/with_search.html.erb +64 -0
  50. data/lib/generators/bootstrap/snippets/templates/features/columns_with_icons.html.erb +46 -0
  51. data/lib/generators/bootstrap/snippets/templates/features/custom_cards.html.erb +79 -0
  52. data/lib/generators/bootstrap/snippets/templates/features/hanging_icons.html.erb +41 -0
  53. data/lib/generators/bootstrap/snippets/templates/features/icon_grid.html.erb +77 -0
  54. data/lib/generators/bootstrap/snippets/templates/features/with_title.html.erb +50 -0
  55. data/lib/generators/bootstrap/snippets/templates/footers/columns.html.erb +43 -0
  56. data/lib/generators/bootstrap/snippets/templates/footers/simple.html.erb +15 -0
  57. data/lib/generators/bootstrap/snippets/templates/footers/with_brand.html.erb +22 -0
  58. data/lib/generators/bootstrap/snippets/templates/footers/with_nav.html.erb +12 -0
  59. data/lib/generators/bootstrap/snippets/templates/footers/with_newsletter.html.erb +62 -0
  60. data/lib/generators/bootstrap/snippets/templates/headers/centered.html.erb +15 -0
  61. data/lib/generators/bootstrap/snippets/templates/headers/dark_double.html.erb +66 -0
  62. data/lib/generators/bootstrap/snippets/templates/headers/dark_search.html.erb +25 -0
  63. data/lib/generators/bootstrap/snippets/templates/headers/double.html.erb +28 -0
  64. data/lib/generators/bootstrap/snippets/templates/headers/grid_dropdown.html.erb +47 -0
  65. data/lib/generators/bootstrap/snippets/templates/headers/light_search.html.erb +34 -0
  66. data/lib/generators/bootstrap/snippets/templates/headers/nav_pills.html.erb +11 -0
  67. data/lib/generators/bootstrap/snippets/templates/headers/with_auth_buttons.html.erb +22 -0
  68. data/lib/generators/bootstrap/snippets/templates/heroes/centered.html.erb +13 -0
  69. data/lib/generators/bootstrap/snippets/templates/heroes/centered_screenshot.html.erb +17 -0
  70. data/lib/generators/bootstrap/snippets/templates/heroes/cropped_image.html.erb +17 -0
  71. data/lib/generators/bootstrap/snippets/templates/heroes/dark.html.erb +14 -0
  72. data/lib/generators/bootstrap/snippets/templates/heroes/signup_form.html.erb +26 -0
  73. data/lib/generators/bootstrap/snippets/templates/heroes/with_image.html.erb +17 -0
  74. data/lib/generators/bootstrap/snippets/templates/icons/_bootstrap_icons.html.erb +134 -0
  75. data/lib/generators/bootstrap/snippets/templates/jumbotrons/basic.html.erb +10 -0
  76. data/lib/generators/bootstrap/snippets/templates/jumbotrons/full_width.html.erb +12 -0
  77. data/lib/generators/bootstrap/snippets/templates/jumbotrons/placeholder.html.erb +13 -0
  78. data/lib/generators/bootstrap/snippets/templates/jumbotrons/with_icon.html.erb +22 -0
  79. data/lib/generators/bootstrap/snippets/templates/list-groups/checkable.html.erb +24 -0
  80. data/lib/generators/bootstrap/snippets/templates/list-groups/checkboxes.html.erb +45 -0
  81. data/lib/generators/bootstrap/snippets/templates/list-groups/checkboxes_expanded.html.erb +52 -0
  82. data/lib/generators/bootstrap/snippets/templates/list-groups/radios.html.erb +32 -0
  83. data/lib/generators/bootstrap/snippets/templates/list-groups/with_avatars.html.erb +36 -0
  84. data/lib/generators/bootstrap/snippets/templates/modals/confirm.html.erb +18 -0
  85. data/lib/generators/bootstrap/snippets/templates/modals/sheet.html.erb +19 -0
  86. data/lib/generators/bootstrap/snippets/templates/modals/signup.html.erb +44 -0
  87. data/lib/generators/bootstrap/snippets/templates/modals/whats_new.html.erb +41 -0
  88. data/lib/generators/bootstrap/snippets/templates/sidebars/collapsible.html.erb +90 -0
  89. data/lib/generators/bootstrap/snippets/templates/sidebars/dark.html.erb +67 -0
  90. data/lib/generators/bootstrap/snippets/templates/sidebars/icon_only.html.erb +59 -0
  91. data/lib/generators/bootstrap/snippets/templates/sidebars/light.html.erb +67 -0
  92. data/lib/generators/bootstrap/snippets/templates/sidebars/list_group.html.erb +94 -0
  93. data/lib/generators/bootstrap/starter/starter_generator.rb +37 -0
  94. data/lib/generators/bootstrap/starter/templates/starter.html.erb +13 -0
  95. data/lib/twitter/bootstrap/rails/bootstrap.rb +1 -0
  96. data/lib/twitter/bootstrap/rails/config.rb +54 -0
  97. data/lib/twitter/bootstrap/rails/engine.rb +0 -8
  98. data/lib/twitter/bootstrap/rails/version.rb +28 -1
  99. data/lib/twitter-bootstrap-rails.rb +0 -1
  100. data/spec/lib/generators/cdn_generator_spec.rb +42 -0
  101. data/spec/lib/generators/install_generator_spec.rb +148 -0
  102. data/spec/lib/generators/layout_generator_spec.rb +124 -0
  103. data/spec/lib/generators/no_hardcoded_versions_spec.rb +45 -0
  104. data/spec/lib/generators/snippet_generators_spec.rb +201 -0
  105. data/spec/lib/generators/starter_generator_spec.rb +54 -0
  106. data/spec/spec_helper.rb +5 -0
  107. data/spec/support/generator_spec_helper.rb +87 -0
  108. data/vendor/assets/javascripts/twitter/bootstrap/bootstrap.bundle.min.js +3 -3
  109. data/vendor/assets/stylesheets/twitter/bootstrap/bootstrap.min.css +3 -3
  110. metadata +99 -123
  111. data/app/assets/fonts/glyphicons-halflings-regular.eot +0 -0
  112. data/app/assets/fonts/glyphicons-halflings-regular.svg +0 -288
  113. data/app/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
  114. data/app/assets/fonts/glyphicons-halflings-regular.woff +0 -0
  115. data/app/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
  116. data/app/helpers/glyph_helper.rb +0 -23
  117. data/lib/generators/bootstrap/install/templates/bootstrap.coffee +0 -3
  118. data/lib/generators/bootstrap/install/templates/bootstrap_and_overrides.less +0 -21
  119. data/spec/lib/twitter_bootstrap_rails/glyph_helper_spec.rb +0 -24
  120. data/vendor/assets/stylesheets/twitter-bootstrap-static/bootstrap.css.erb +0 -6684
  121. data/vendor/static-source/bootstrap.less +0 -1
  122. data/vendor/static-source/sprites.less +0 -6
  123. data/vendor/toolkit/twitter/bootstrap/alerts.less +0 -73
  124. data/vendor/toolkit/twitter/bootstrap/badges.less +0 -66
  125. data/vendor/toolkit/twitter/bootstrap/bootstrap.less +0 -55
  126. data/vendor/toolkit/twitter/bootstrap/breadcrumbs.less +0 -26
  127. data/vendor/toolkit/twitter/bootstrap/button-groups.less +0 -244
  128. data/vendor/toolkit/twitter/bootstrap/buttons.less +0 -166
  129. data/vendor/toolkit/twitter/bootstrap/carousel.less +0 -270
  130. data/vendor/toolkit/twitter/bootstrap/close.less +0 -34
  131. data/vendor/toolkit/twitter/bootstrap/code.less +0 -69
  132. data/vendor/toolkit/twitter/bootstrap/component-animations.less +0 -33
  133. data/vendor/toolkit/twitter/bootstrap/dropdowns.less +0 -216
  134. data/vendor/toolkit/twitter/bootstrap/forms.less +0 -613
  135. data/vendor/toolkit/twitter/bootstrap/glyphicons.less +0 -305
  136. data/vendor/toolkit/twitter/bootstrap/grid.less +0 -84
  137. data/vendor/toolkit/twitter/bootstrap/input-groups.less +0 -171
  138. data/vendor/toolkit/twitter/bootstrap/jumbotron.less +0 -54
  139. data/vendor/toolkit/twitter/bootstrap/labels.less +0 -64
  140. data/vendor/toolkit/twitter/bootstrap/list-group.less +0 -130
  141. data/vendor/toolkit/twitter/bootstrap/media.less +0 -66
  142. data/vendor/toolkit/twitter/bootstrap/mixins/alerts.less +0 -14
  143. data/vendor/toolkit/twitter/bootstrap/mixins/background-variant.less +0 -9
  144. data/vendor/toolkit/twitter/bootstrap/mixins/border-radius.less +0 -18
  145. data/vendor/toolkit/twitter/bootstrap/mixins/buttons.less +0 -65
  146. data/vendor/toolkit/twitter/bootstrap/mixins/center-block.less +0 -7
  147. data/vendor/toolkit/twitter/bootstrap/mixins/clearfix.less +0 -22
  148. data/vendor/toolkit/twitter/bootstrap/mixins/forms.less +0 -85
  149. data/vendor/toolkit/twitter/bootstrap/mixins/gradients.less +0 -59
  150. data/vendor/toolkit/twitter/bootstrap/mixins/grid-framework.less +0 -91
  151. data/vendor/toolkit/twitter/bootstrap/mixins/grid.less +0 -122
  152. data/vendor/toolkit/twitter/bootstrap/mixins/hide-text.less +0 -21
  153. data/vendor/toolkit/twitter/bootstrap/mixins/image.less +0 -33
  154. data/vendor/toolkit/twitter/bootstrap/mixins/labels.less +0 -12
  155. data/vendor/toolkit/twitter/bootstrap/mixins/list-group.less +0 -30
  156. data/vendor/toolkit/twitter/bootstrap/mixins/nav-divider.less +0 -10
  157. data/vendor/toolkit/twitter/bootstrap/mixins/nav-vertical-align.less +0 -9
  158. data/vendor/toolkit/twitter/bootstrap/mixins/opacity.less +0 -8
  159. data/vendor/toolkit/twitter/bootstrap/mixins/pagination.less +0 -24
  160. data/vendor/toolkit/twitter/bootstrap/mixins/panels.less +0 -24
  161. data/vendor/toolkit/twitter/bootstrap/mixins/progress-bar.less +0 -10
  162. data/vendor/toolkit/twitter/bootstrap/mixins/reset-filter.less +0 -8
  163. data/vendor/toolkit/twitter/bootstrap/mixins/reset-text.less +0 -18
  164. data/vendor/toolkit/twitter/bootstrap/mixins/resize.less +0 -6
  165. data/vendor/toolkit/twitter/bootstrap/mixins/responsive-visibility.less +0 -15
  166. data/vendor/toolkit/twitter/bootstrap/mixins/size.less +0 -10
  167. data/vendor/toolkit/twitter/bootstrap/mixins/tab-focus.less +0 -9
  168. data/vendor/toolkit/twitter/bootstrap/mixins/table-row.less +0 -28
  169. data/vendor/toolkit/twitter/bootstrap/mixins/text-emphasis.less +0 -9
  170. data/vendor/toolkit/twitter/bootstrap/mixins/text-overflow.less +0 -8
  171. data/vendor/toolkit/twitter/bootstrap/mixins/vendor-prefixes.less +0 -227
  172. data/vendor/toolkit/twitter/bootstrap/mixins.less +0 -40
  173. data/vendor/toolkit/twitter/bootstrap/modals.less +0 -150
  174. data/vendor/toolkit/twitter/bootstrap/navbar.less +0 -660
  175. data/vendor/toolkit/twitter/bootstrap/navs.less +0 -242
  176. data/vendor/toolkit/twitter/bootstrap/normalize.less +0 -424
  177. data/vendor/toolkit/twitter/bootstrap/pager.less +0 -54
  178. data/vendor/toolkit/twitter/bootstrap/pagination.less +0 -89
  179. data/vendor/toolkit/twitter/bootstrap/panels.less +0 -271
  180. data/vendor/toolkit/twitter/bootstrap/popovers.less +0 -131
  181. data/vendor/toolkit/twitter/bootstrap/print.less +0 -101
  182. data/vendor/toolkit/twitter/bootstrap/progress-bars.less +0 -87
  183. data/vendor/toolkit/twitter/bootstrap/responsive-embed.less +0 -35
  184. data/vendor/toolkit/twitter/bootstrap/responsive-utilities.less +0 -194
  185. data/vendor/toolkit/twitter/bootstrap/scaffolding.less +0 -161
  186. data/vendor/toolkit/twitter/bootstrap/tables.less +0 -234
  187. data/vendor/toolkit/twitter/bootstrap/theme.less +0 -291
  188. data/vendor/toolkit/twitter/bootstrap/thumbnails.less +0 -36
  189. data/vendor/toolkit/twitter/bootstrap/tooltip.less +0 -101
  190. data/vendor/toolkit/twitter/bootstrap/type.less +0 -302
  191. data/vendor/toolkit/twitter/bootstrap/utilities.less +0 -55
  192. data/vendor/toolkit/twitter/bootstrap/variables.less +0 -1751
  193. data/vendor/toolkit/twitter/bootstrap/wells.less +0 -29
  194. data/vendor/toolkit/twitter/bootstrap_base.less +0 -2
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Badges from https://getbootstrap.com/docs/5.3/examples/badges/
6
+ class BadgeGenerator < SnippetBase
7
+ snippet_category "badges"
8
+
9
+ desc "Copies a Bootstrap badges snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Breadcrumbs from https://getbootstrap.com/docs/5.3/examples/breadcrumbs/
6
+ class BreadcrumbGenerator < SnippetBase
7
+ snippet_category "breadcrumbs"
8
+
9
+ desc "Copies a Bootstrap breadcrumbs snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Buttons from https://getbootstrap.com/docs/5.3/examples/buttons/
6
+ class ButtonGenerator < SnippetBase
7
+ snippet_category "buttons"
8
+
9
+ desc "Copies a Bootstrap buttons snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ require 'rails/generators'
2
+ require 'twitter/bootstrap/rails/version'
3
+ require 'generators/bootstrap/cdn_tags'
4
+
5
+ module Bootstrap
6
+ module Generators
7
+ # Prints the jsDelivr tags for pasting into a layout the user already owns.
8
+ # Writes nothing to disk.
9
+ class CdnGenerator < ::Rails::Generators::Base
10
+ include CdnTags
11
+
12
+ desc "Prints the Bootstrap #{Twitter::Bootstrap::Rails::BOOTSTRAP_VERSION} CDN tags"
13
+
14
+ class_option :css, :type => :boolean, :default => false,
15
+ :desc => 'Print only the stylesheet link'
16
+ class_option :js, :type => :boolean, :default => false,
17
+ :desc => 'Print only the JavaScript bundle script'
18
+ class_option :'separate-popper', :type => :boolean, :default => false,
19
+ :desc => 'Print Popper and bootstrap.js as separate tags instead of the bundle'
20
+
21
+ def print_tags
22
+ say tags.join("\n")
23
+ end
24
+
25
+ private
26
+
27
+ def tags
28
+ return [css_tag] if options[:css] && !options[:js]
29
+ return [javascript_tags] if options[:js] && !options[:css]
30
+
31
+ [css_tag, javascript_tags]
32
+ end
33
+
34
+ def javascript_tags
35
+ options[:'separate-popper'] ? separate_popper_tags : bundle_tag
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ require "twitter/bootstrap/rails/version"
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Renders the jsDelivr tags from the Introduction page, built from the
6
+ # constants in Twitter::Bootstrap::Rails so no template hardcodes a version
7
+ # or an integrity hash.
8
+ module CdnTags
9
+ def css_tag
10
+ entry = cdn(:css)
11
+ %{<link href="#{entry[:url]}" rel="stylesheet" integrity="#{entry[:integrity]}" crossorigin="anonymous">}
12
+ end
13
+
14
+ def bundle_tag
15
+ script_tag(:bundle)
16
+ end
17
+
18
+ def js_tag
19
+ script_tag(:js)
20
+ end
21
+
22
+ def popper_tag
23
+ script_tag(:popper)
24
+ end
25
+
26
+ # Popper and bootstrap.js as the separate pair, in the docs' order.
27
+ def separate_popper_tags
28
+ [popper_tag, js_tag].join("\n")
29
+ end
30
+
31
+ private
32
+
33
+ def script_tag(key)
34
+ entry = cdn(key)
35
+ %{<script src="#{entry[:url]}" integrity="#{entry[:integrity]}" crossorigin="anonymous"></script>}
36
+ end
37
+
38
+ def cdn(key)
39
+ Twitter::Bootstrap::Rails::BOOTSTRAP_CDN.fetch(key)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Dropdowns from https://getbootstrap.com/docs/5.3/examples/dropdowns/
6
+ class DropdownGenerator < SnippetBase
7
+ snippet_category "dropdowns"
8
+
9
+ desc "Copies a Bootstrap dropdowns snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Features from https://getbootstrap.com/docs/5.3/examples/features/
6
+ class FeaturesGenerator < SnippetBase
7
+ snippet_category "features"
8
+
9
+ desc "Copies a Bootstrap features snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Footers from https://getbootstrap.com/docs/5.3/examples/footers/
6
+ class FooterGenerator < SnippetBase
7
+ snippet_category "footers"
8
+
9
+ desc "Copies a Bootstrap footers snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Headers from https://getbootstrap.com/docs/5.3/examples/headers/
6
+ class HeaderGenerator < SnippetBase
7
+ snippet_category "headers"
8
+
9
+ desc "Copies a Bootstrap headers snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Heroes from https://getbootstrap.com/docs/5.3/examples/heroes/
6
+ class HeroGenerator < SnippetBase
7
+ snippet_category "heroes"
8
+
9
+ desc "Copies a Bootstrap heroes snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -1,104 +1,163 @@
1
1
  require 'rails/generators'
2
2
  require 'fileutils'
3
+ require 'twitter/bootstrap/rails/version'
3
4
 
4
5
  module Bootstrap
5
6
  module Generators
6
7
  class InstallGenerator < ::Rails::Generators::Base
7
8
 
9
+ # Raised when a dist file that should ship with the gem is missing, rather
10
+ # than silently installing nothing.
11
+ class MissingAssetError < StandardError; end
12
+
8
13
  source_root File.expand_path("../templates", __FILE__)
9
- desc "This generator installs Bootstrap to Asset Pipeline"
10
- argument :stylesheets_type, :type => :string, :default => 'static', :banner => '*less or static'
11
- class_option :'no-coffeescript', :type => :boolean, :default => false, :desc => 'Skips coffeescript replacement into app generators'
14
+ desc "This generator installs Bootstrap #{Twitter::Bootstrap::Rails::BOOTSTRAP_VERSION} to the Asset Pipeline"
15
+ argument :asset_mode, :type => :string, :default => 'static',
16
+ :banner => 'static or cdn',
17
+ :desc => 'static vendors Bootstrap into the app; cdn links to jsDelivr instead'
18
+
19
+ VENDORED_ASSETS = [
20
+ ['vendor/assets/stylesheets/twitter/bootstrap/bootstrap.min.css',
21
+ 'app/assets/stylesheets/twitter/bootstrap/bootstrap.min.css'],
22
+ ['vendor/assets/javascripts/twitter/bootstrap/bootstrap.bundle.min.js',
23
+ 'app/assets/javascripts/twitter/bootstrap/bootstrap.bundle.min.js']
24
+ ].freeze
25
+
26
+ def validate_asset_mode
27
+ return if %w[static cdn].include?(asset_mode)
28
+
29
+ raise ::Rails::Generators::Error,
30
+ "Unknown asset mode #{asset_mode.inspect}. Expected 'static' or 'cdn'."
31
+ end
12
32
 
13
33
  def add_assets
34
+ return if cdn?
35
+ # Propshaft has no require directives to add; bootstrap:layout links the
36
+ # vendored files explicitly instead.
37
+ return if propshaft?
14
38
 
15
39
  js_manifest = 'app/assets/javascripts/application.js'
16
40
 
17
- if File.exist?(js_manifest)
18
- insert_into_file js_manifest, "//= require twitter/bootstrap\n", :after => "application\n"
41
+ if exists_in_app?(js_manifest)
42
+ add_require(js_manifest,
43
+ "//= require twitter/bootstrap/bootstrap.bundle.min\n",
44
+ "application\n",
45
+ 'twitter/bootstrap')
19
46
  else
20
47
  copy_file "application.js", js_manifest
21
48
  end
22
49
 
23
50
  css_manifest = 'app/assets/stylesheets/application.css'
24
51
 
25
- if File.exist?(css_manifest)
26
- content = File.read(css_manifest)
27
- unless content.include?('bootstrap')
28
- style_require_block = " *= require bootstrap\n"
29
- insert_into_file css_manifest, style_require_block, :after => "require_self\n"
30
- end
52
+ if exists_in_app?(css_manifest)
53
+ add_require(css_manifest,
54
+ " *= require bootstrap_and_overrides\n",
55
+ "require_self\n",
56
+ 'bootstrap')
31
57
  else
32
- copy_file "application.css", "app/assets/stylesheets/application.css"
58
+ copy_file "application.css", css_manifest
33
59
  end
34
-
35
- copy_bootstrap_assets
36
-
37
60
  end
38
61
 
39
62
  def copy_bootstrap_assets
40
- gem_root = File.expand_path("../../../../..", __FILE__)
41
- bootstrap_css_src = "#{gem_root}/vendor/assets/stylesheets/twitter/bootstrap"
42
- bootstrap_js_src = "#{gem_root}/vendor/assets/javascripts/twitter/bootstrap"
43
-
44
- css_dest = "app/assets/stylesheets/twitter/bootstrap"
45
- js_dest = "app/assets/javascripts/twitter/bootstrap"
46
-
47
- FileUtils.mkdir_p(css_dest)
48
- FileUtils.mkdir_p(js_dest)
49
-
50
- Dir.glob("#{bootstrap_css_src}/*").each do |src|
51
- dest = "#{css_dest}/#{File.basename(src)}"
52
- FileUtils.cp(src, dest)
53
- end
54
-
55
- Dir.glob("#{bootstrap_js_src}/*").each do |src|
56
- dest = "#{js_dest}/#{File.basename(src)}"
57
- FileUtils.cp(src, dest)
63
+ return if cdn?
64
+
65
+ VENDORED_ASSETS.each do |relative_source, destination|
66
+ source = File.join(gem_root, relative_source)
67
+
68
+ unless File.file?(source)
69
+ raise MissingAssetError,
70
+ "Bootstrap #{Twitter::Bootstrap::Rails::BOOTSTRAP_VERSION} asset missing from the gem: " \
71
+ "#{relative_source}. The gem install looks incomplete; reinstall twitter-bootstrap-rails."
72
+ end
73
+
74
+ create_file destination, File.binread(source)
58
75
  end
59
76
  end
60
77
 
61
78
  def add_bootstrap
62
- if use_coffeescript?
63
- copy_file "bootstrap.coffee", "app/assets/javascripts/bootstrap.js.coffee"
64
- else
65
- copy_file "bootstrap.js", "app/assets/javascripts/bootstrap.js"
66
- end
67
- if use_less?
68
- copy_file "bootstrap_and_overrides.less", "app/assets/stylesheets/bootstrap_and_overrides.css.less"
69
- else
70
- copy_file "bootstrap_and_overrides.css", "app/assets/stylesheets/bootstrap_and_overrides.css"
71
- end
79
+ return if cdn?
80
+ return if propshaft?
81
+
82
+ copy_file "bootstrap.js", "app/assets/javascripts/bootstrap.js"
83
+ copy_file "bootstrap_and_overrides.css", "app/assets/stylesheets/bootstrap_and_overrides.css"
84
+ end
85
+
86
+ def add_cdn_initializer
87
+ return unless cdn?
88
+
89
+ create_file "config/initializers/bootstrap.rb", <<~RUBY
90
+ # Bootstrap's CSS and JS are loaded from jsDelivr rather than vendored into
91
+ # this app. `rails g bootstrap:layout` reads this to emit CDN tags by default.
92
+ Twitter::Bootstrap::Rails.asset_mode = :cdn
93
+ RUBY
72
94
  end
73
95
 
74
96
  def add_locale
75
- if File.exist?("config/locales/en.bootstrap.yml")
76
- localez = File.read("config/locales/en.bootstrap.yml")
77
- insert_into_file "config/locales/en.bootstrap.yml", localez, :after => "en\n"
97
+ return if exists_in_app?("config/locales/en.bootstrap.yml")
98
+
99
+ copy_file "en.bootstrap.yml", "config/locales/en.bootstrap.yml"
100
+ end
101
+
102
+ def cleanup_legacy
103
+ return unless exists_in_app?('app/assets/stylesheets/application.css')
104
+
105
+ gsub_file("app/assets/stylesheets/application.css", %r|\s*\*=\s*twitter/bootstrap\s*\n|, "", :verbose => false)
106
+ end
107
+
108
+ def report
109
+ version = Twitter::Bootstrap::Rails::BOOTSTRAP_VERSION
110
+
111
+ if cdn?
112
+ say "Bootstrap #{version} will be loaded from jsDelivr. " \
113
+ "Run `rails g bootstrap:layout` to generate a layout with the CDN tags."
114
+ elsif propshaft?
115
+ say "Bootstrap #{version} vendored for Propshaft. " \
116
+ "Run `rails g bootstrap:layout` to generate a layout that links it."
78
117
  else
79
- copy_file "en.bootstrap.yml", "config/locales/en.bootstrap.yml"
118
+ say "Bootstrap #{version} vendored into the asset pipeline."
80
119
  end
81
120
  end
82
121
 
83
- def cleanup_legacy
84
- gsub_file("app/assets/stylesheets/application.css", %r|\s*\*=\s*twitter/bootstrap\s*\n|, "")
85
- if File.exist?('app/assets/stylesheets/bootstrap_override.css.less')
86
- puts <<-EOM
87
- Warning:
88
- app/assets/stylesheets/bootstrap_override.css.less exists
89
- It should be removed, as it has been superceded by app/assets/stylesheets/bootstrap_and_overrides.css.less
90
- EOM
122
+ private
123
+
124
+ def cdn?
125
+ asset_mode == 'cdn'
126
+ end
127
+
128
+ def propshaft?
129
+ Twitter::Bootstrap::Rails.propshaft?
130
+ end
131
+
132
+ def gem_root
133
+ File.expand_path("../../../../..", __FILE__)
134
+ end
135
+
136
+ # Adds a Sprockets require to an existing manifest. Apps on Propshaft (the
137
+ # Rails 8 default) have no Sprockets directives to anchor to, so rather than
138
+ # letting the insert quietly fail, say what to add by hand.
139
+ def add_require(manifest, directive, anchor, marker)
140
+ content = read_from_app(manifest)
141
+ return if content.include?(marker)
142
+
143
+ if content.include?(anchor)
144
+ insert_into_file manifest, directive, :after => anchor
145
+ else
146
+ say_status :warn,
147
+ "#{manifest} has no `#{anchor.strip}` directive to anchor to — it is probably not a " \
148
+ "Sprockets manifest. Add this line yourself: #{directive.strip}",
149
+ :yellow
91
150
  end
92
151
  end
93
152
 
94
- private
95
- def use_less?
96
- (defined?(Less) && (stylesheets_type!='static') ) || (stylesheets_type=='less')
153
+ # Paths in a generator are relative to the destination root, not the
154
+ # working directory, so they have to be resolved before touching the disk.
155
+ def exists_in_app?(relative)
156
+ File.exist?(File.join(destination_root, relative))
97
157
  end
98
158
 
99
- def use_coffeescript?
100
- return false if options[:'no-coffeescript']
101
- ::Rails.configuration.app_generators.rails[:javascript_engine] == :coffee
159
+ def read_from_app(relative)
160
+ File.read(File.join(destination_root, relative))
102
161
  end
103
162
  end
104
163
  end
@@ -4,5 +4,5 @@
4
4
  // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5
5
  // the compiled file.
6
6
  //
7
- //= require twitter/bootstrap
7
+ //= require twitter/bootstrap/bootstrap.bundle.min
8
8
  //= require_tree .
@@ -1,4 +1,11 @@
1
- jQuery(function() {
2
- $("a[rel~=popover], .has-popover").popover();
3
- $("a[rel~=tooltip], .has-tooltip").tooltip();
1
+ // Bootstrap 5 has no jQuery dependency. Tooltips and popovers are opt-in, so
2
+ // initialize the elements marked up with data-bs-toggle here.
3
+ document.addEventListener("DOMContentLoaded", function () {
4
+ document.querySelectorAll('[data-bs-toggle="tooltip"]').forEach(function (el) {
5
+ new bootstrap.Tooltip(el);
6
+ });
7
+
8
+ document.querySelectorAll('[data-bs-toggle="popover"]').forEach(function (el) {
9
+ new bootstrap.Popover(el);
10
+ });
4
11
  });
@@ -1,5 +1,5 @@
1
1
  /*
2
- *= require twitter-bootstrap-static/bootstrap
2
+ *= require twitter/bootstrap/bootstrap.min
3
3
 
4
- Bootstrap 5 no longer includes Glyphicons
4
+ Bootstrap 5 no longer ships Glyphicons. Add your own overrides below.
5
5
  */
@@ -0,0 +1,13 @@
1
+ require 'generators/bootstrap/snippets/snippet_base'
2
+
3
+ module Bootstrap
4
+ module Generators
5
+ # Jumbotrons from https://getbootstrap.com/docs/5.3/examples/jumbotrons/
6
+ class JumbotronGenerator < SnippetBase
7
+ snippet_category "jumbotrons"
8
+
9
+ desc "Copies a Bootstrap jumbotrons snippet into your views. " \
10
+ "Run with --list to see the variants."
11
+ end
12
+ end
13
+ end
@@ -1,20 +1,84 @@
1
1
  require 'rails/generators'
2
+ require 'twitter/bootstrap/rails/version'
3
+ require 'twitter/bootstrap/rails/config'
4
+ require 'generators/bootstrap/cdn_tags'
2
5
 
3
6
  module Bootstrap
4
7
  module Generators
5
8
  class LayoutGenerator < ::Rails::Generators::Base
9
+ include CdnTags
10
+
6
11
  source_root File.expand_path("../templates", __FILE__)
7
- desc "This generator generates layout file with navigation."
12
+ desc "This generator generates a Bootstrap #{Twitter::Bootstrap::Rails::BOOTSTRAP_VERSION} layout file with navigation."
8
13
  argument :layout_name, :type => :string, :default => "application"
9
14
 
15
+ class_option :cdn, :type => :boolean, :default => nil,
16
+ :desc => 'Link Bootstrap from jsDelivr instead of the asset pipeline ' \
17
+ '(defaults to the mode recorded by bootstrap:install)'
18
+ class_option :'separate-popper', :type => :boolean, :default => false,
19
+ :desc => 'With --cdn, emit Popper and bootstrap.js as separate tags instead of the bundle'
20
+
10
21
  attr_reader :app_name
11
22
 
23
+ def warn_about_ignored_options
24
+ return unless options[:'separate-popper'] && !cdn?
25
+
26
+ say_status :warn,
27
+ "--separate-popper only applies with --cdn; the vendored asset pipeline ships the bundle. Ignoring.",
28
+ :yellow
29
+ end
30
+
12
31
  def generate_layout
13
32
  app = ::Rails.application
14
33
  @app_name = app.class.to_s.split("::").first
15
34
  ext = app.config.generators.options[:rails][:template_engine] || :erb
16
35
  template "layout.html.#{ext}", "app/views/layouts/#{layout_name}.html.#{ext}"
17
36
  end
37
+
38
+ private
39
+
40
+ def cdn?
41
+ return options[:cdn] unless options[:cdn].nil?
42
+
43
+ Twitter::Bootstrap::Rails.cdn?
44
+ end
45
+
46
+ def separate_popper?
47
+ options[:'separate-popper'] && cdn?
48
+ end
49
+
50
+ # The end-of-body CDN script tag(s): one bundle, or the Popper pair.
51
+ def script_tags
52
+ separate_popper? ? separate_popper_tags : bundle_tag
53
+ end
54
+
55
+ # Under Sprockets the manifests carry `require` directives, so linking
56
+ # "application" is enough. Propshaft has no directives, so the vendored
57
+ # Bootstrap files have to be named explicitly or they never load.
58
+ def propshaft?
59
+ Twitter::Bootstrap::Rails.propshaft?
60
+ end
61
+
62
+ def stylesheet_arguments
63
+ propshaft? ? '"twitter/bootstrap/bootstrap.min", "application"' : '"application"'
64
+ end
65
+
66
+ # Propshaft apps (Rails 8) serve their own JavaScript through importmap, so
67
+ # there is no "application.js" asset to link — only Bootstrap's bundle.
68
+ def javascript_arguments
69
+ propshaft? ? '"twitter/bootstrap/bootstrap.bundle.min"' : '"application"'
70
+ end
71
+
72
+ # Raw tags indented to sit at the right depth. Haml treats a line starting
73
+ # with a plain character as literal text, so it needs nothing more.
74
+ def indent_tags(tags, indent)
75
+ tags.split("\n").map { |line| "#{indent}#{line}" }.join("\n")
76
+ end
77
+
78
+ # Slim needs each raw HTML line introduced by a `|` text marker.
79
+ def slim_tags(tags, indent)
80
+ tags.split("\n").map { |line| "#{indent}| #{line}" }.join("\n")
81
+ end
18
82
  end
19
83
  end
20
84
  end
@@ -1,16 +1,17 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
6
  <title><%%= content_for?(:title) ? yield(:title) : "<%= app_name %>" %></title>
7
7
  <%%= csrf_meta_tags %>
8
+ <% if cdn? -%>
8
9
 
9
- <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
10
+ <%= css_tag %>
11
+ <% else -%>
10
12
 
11
- <%%= stylesheet_link_tag "application", :media => "all" %>
12
-
13
- <%%= javascript_include_tag "application" %>
13
+ <%%= stylesheet_link_tag <%= stylesheet_arguments %>, :media => "all" %>
14
+ <% end -%>
14
15
  </head>
15
16
  <body>
16
17
 
@@ -21,8 +22,8 @@
21
22
  <span class="navbar-toggler-icon"></span>
22
23
  </button>
23
24
  <div class="collapse navbar-collapse" id="navbarNav">
24
- <ul class="nav navbar-nav">
25
- <li><%%= link_to "Home", "/" %></li>
25
+ <ul class="navbar-nav">
26
+ <li class="nav-item"><%%= link_to "Home", "/", :class => "nav-link" %></li>
26
27
  </ul>
27
28
  </div>
28
29
  </div>
@@ -33,10 +34,14 @@
33
34
  <%%= yield %>
34
35
 
35
36
  <footer class="mt-5 py-3 border-top">
36
- <p class="text-muted">&copy; Company <%= Date.today.year %></p>
37
+ <p class="text-body-secondary">&copy; Company <%%= Time.current.year %></p>
37
38
  </footer>
38
39
  </div>
39
40
 
40
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
41
+ <% if cdn? -%>
42
+ <%= indent_tags(script_tags, " ") %>
43
+ <% else -%>
44
+ <%%= javascript_include_tag <%= javascript_arguments %> %>
45
+ <% end -%>
41
46
  </body>
42
47
  </html>