bootstrap-cells 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.gitlab-ci.yml +13 -0
  4. data/.rspec +2 -0
  5. data/.rubocop.yml +27 -0
  6. data/CHANGELOG +29 -0
  7. data/Gemfile +6 -0
  8. data/Gemfile.lock +200 -0
  9. data/Rakefile +8 -0
  10. data/app/assets/javascripts/bootstrap-cells/add_many_event_listeners.js +11 -0
  11. data/app/assets/javascripts/bootstrap-cells/index.js +3 -0
  12. data/app/assets/stylesheets/_bootstrap-cells.scss +7 -0
  13. data/app/views/kaminari/bootstrap/_first_page.html.erb +15 -0
  14. data/app/views/kaminari/bootstrap/_gap.html.erb +12 -0
  15. data/app/views/kaminari/bootstrap/_last_page.html.erb +16 -0
  16. data/app/views/kaminari/bootstrap/_next_page.html.erb +16 -0
  17. data/app/views/kaminari/bootstrap/_page.html.erb +17 -0
  18. data/app/views/kaminari/bootstrap/_paginator.html.erb +32 -0
  19. data/app/views/kaminari/bootstrap/_prev_page.html.erb +16 -0
  20. data/bin/console +15 -0
  21. data/bin/setup +8 -0
  22. data/bootstrap-cells.gemspec +36 -0
  23. data/lib/bootstrap-cells.rb +16 -0
  24. data/lib/bootstrap-cells/cells/alert/body.erb +7 -0
  25. data/lib/bootstrap-cells/cells/alert/show.erb +7 -0
  26. data/lib/bootstrap-cells/cells/alert/title.erb +9 -0
  27. data/lib/bootstrap-cells/cells/alert_cell.rb +39 -0
  28. data/lib/bootstrap-cells/cells/base_cell.rb +43 -0
  29. data/lib/bootstrap-cells/cells/button/show.erb +17 -0
  30. data/lib/bootstrap-cells/cells/button_cell.rb +41 -0
  31. data/lib/bootstrap-cells/cells/card/block.erb +14 -0
  32. data/lib/bootstrap-cells/cells/card/block_body.erb +5 -0
  33. data/lib/bootstrap-cells/cells/card/block_subtitle.erb +5 -0
  34. data/lib/bootstrap-cells/cells/card/block_text.erb +5 -0
  35. data/lib/bootstrap-cells/cells/card/block_title.erb +5 -0
  36. data/lib/bootstrap-cells/cells/card/footer.erb +9 -0
  37. data/lib/bootstrap-cells/cells/card/header.erb +9 -0
  38. data/lib/bootstrap-cells/cells/card/img_bottom.erb +9 -0
  39. data/lib/bootstrap-cells/cells/card/img_top.erb +9 -0
  40. data/lib/bootstrap-cells/cells/card/list_group.erb +9 -0
  41. data/lib/bootstrap-cells/cells/card/show.erb +9 -0
  42. data/lib/bootstrap-cells/cells/card/table.erb +9 -0
  43. data/lib/bootstrap-cells/cells/card_cell.rb +152 -0
  44. data/lib/bootstrap-cells/cells/column/td.erb +1 -0
  45. data/lib/bootstrap-cells/cells/column/th.erb +9 -0
  46. data/lib/bootstrap-cells/cells/column_cell.rb +49 -0
  47. data/lib/bootstrap-cells/cells/field/required_field.scss +5 -0
  48. data/lib/bootstrap-cells/cells/field/show.erb +15 -0
  49. data/lib/bootstrap-cells/cells/field_cell.rb +96 -0
  50. data/lib/bootstrap-cells/cells/fields_for/form.scss +12 -0
  51. data/lib/bootstrap-cells/cells/fields_for/form_horizontal.scss +33 -0
  52. data/lib/bootstrap-cells/cells/fields_for/show.erb +3 -0
  53. data/lib/bootstrap-cells/cells/fields_for_cell.rb +15 -0
  54. data/lib/bootstrap-cells/cells/kv_horizontal/show.erb +17 -0
  55. data/lib/bootstrap-cells/cells/kv_horizontal_cell.rb +34 -0
  56. data/lib/bootstrap-cells/cells/kv_vertical/show.erb +17 -0
  57. data/lib/bootstrap-cells/cells/kv_vertical_cell.rb +32 -0
  58. data/lib/bootstrap-cells/cells/modal/body.erb +9 -0
  59. data/lib/bootstrap-cells/cells/modal/button.erb +9 -0
  60. data/lib/bootstrap-cells/cells/modal/content.erb +12 -0
  61. data/lib/bootstrap-cells/cells/modal/footer.erb +10 -0
  62. data/lib/bootstrap-cells/cells/modal/header.erb +12 -0
  63. data/lib/bootstrap-cells/cells/modal/modal.js +15 -0
  64. data/lib/bootstrap-cells/cells/modal/show.erb +9 -0
  65. data/lib/bootstrap-cells/cells/modal_cell.rb +64 -0
  66. data/lib/bootstrap-cells/cells/pages/pages.scss +4 -0
  67. data/lib/bootstrap-cells/cells/pages/show.erb +3 -0
  68. data/lib/bootstrap-cells/cells/pages_cell.rb +16 -0
  69. data/lib/bootstrap-cells/cells/table/nubbin.scss +40 -0
  70. data/lib/bootstrap-cells/cells/table/show.erb +7 -0
  71. data/lib/bootstrap-cells/cells/table/table_sort.scss +17 -0
  72. data/lib/bootstrap-cells/cells/table/table_striped_nested.scss +8 -0
  73. data/lib/bootstrap-cells/cells/table/tbody.erb +3 -0
  74. data/lib/bootstrap-cells/cells/table/tbody_button_for_nested_row.erb +9 -0
  75. data/lib/bootstrap-cells/cells/table/tbody_final_row.erb +9 -0
  76. data/lib/bootstrap-cells/cells/table/tbody_first_row.erb +9 -0
  77. data/lib/bootstrap-cells/cells/table/tbody_nested_row.erb +6 -0
  78. data/lib/bootstrap-cells/cells/table/tbody_rows.erb +35 -0
  79. data/lib/bootstrap-cells/cells/table/thead.erb +11 -0
  80. data/lib/bootstrap-cells/cells/table_cell.rb +68 -0
  81. data/lib/bootstrap-cells/cells/tabs/show.erb +19 -0
  82. data/lib/bootstrap-cells/cells/tabs_cell.rb +40 -0
  83. data/lib/bootstrap-cells/engine.rb +9 -0
  84. metadata +307 -0
@@ -0,0 +1,16 @@
1
+ <%# Link to the "Previous" page
2
+ - available local variables
3
+ url: url to the previous page
4
+ current_page: a page object for the currently displayed page
5
+ num_pages: total number of pages
6
+ per_page: number of items to fetch per page
7
+ remote: data-remote
8
+ -%>
9
+ <% unless current_page.first? %>
10
+ <li class="prev">
11
+ <%= link_to raw(t 'views.pagination.previous'),
12
+ url,
13
+ rel: 'prev',
14
+ remote: remote %>
15
+ </li>
16
+ <% end %>
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'bootstrap-cells'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,36 @@
1
+ # coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ lib = File.expand_path('../lib', __FILE__)
5
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'bootstrap-cells'
9
+ spec.version = '0.1.5'
10
+ spec.authors = ['Stephen Margheim']
11
+ spec.email = ['margheim@mail.med.upenn.edu']
12
+
13
+ spec.summary = 'Cells for common Bootstrap components.'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features|coverage)/})
17
+ end
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'cells', '~> 4.0'
23
+ spec.add_dependency 'cells-rails', '>= 0.0.8'
24
+ spec.add_dependency 'cells-erb', '>= 0.1.0'
25
+ spec.add_dependency 'kaminari', '~> 1.0'
26
+
27
+ spec.add_development_dependency 'rails', '~> 4.2'
28
+ spec.add_development_dependency 'bundler'
29
+ spec.add_development_dependency 'rake'
30
+ spec.add_development_dependency 'rspec-rails'
31
+ spec.add_development_dependency 'sqlite3'
32
+ spec.add_development_dependency 'simplecov'
33
+ spec.add_development_dependency 'simplecov-console'
34
+ spec.add_development_dependency 'rspec-cells'
35
+ spec.add_development_dependency 'capybara'
36
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cells'
4
+ require 'cells-rails'
5
+ require 'cells-erb'
6
+ require 'kaminari'
7
+
8
+ require 'bootstrap-cells/engine'
9
+ require 'bootstrap-cells/cells/base_cell'
10
+
11
+ Dir[BootstrapCells::Engine.root.join('lib', 'bootstrap-cells', 'cells', '**', '*.rb')].each do |cell|
12
+ require cell
13
+ end
14
+
15
+ module BootstrapCells
16
+ end
@@ -0,0 +1,7 @@
1
+ <% if renderable?(:body) %>
2
+ <%= render_option(:body) %>
3
+ <% else %>
4
+ <%= content_tag(:div, **body_props) do %>
5
+ <%= body_text %>
6
+ <% end %>
7
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <%= content_tag(:div, **alert_props) do %>
2
+ <% if @options[:dismissable] %>
3
+ <button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
4
+ <% end %>
5
+ <%= render :title %>
6
+ <%= render :body %>
7
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if title_text %>
2
+ <% if renderable?(:title) %>
3
+ <%= render_option(:title) %>
4
+ <% else %>
5
+ <%= content_tag(:h4, **title_props) do %>
6
+ <%= title_text %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class AlertCell < BaseCell
4
+ private
5
+
6
+ def alert_props
7
+ defaults = {
8
+ class: c('alert',
9
+ ('alert-dismissable' if options[:dismissable]),
10
+ ("alert-#{options[:type]}" if options[:type]),
11
+ ('border-silver' unless options[:type])),
12
+ role: 'alert',
13
+ }
14
+ merge_props(from: defaults, to: options.dig(:props, :alert))
15
+ end
16
+
17
+ def title_props
18
+ defaults = {
19
+ class: 'alert-title',
20
+ }
21
+ merge_props(from: defaults, to: options.dig(:props, :title))
22
+ end
23
+
24
+ def title_text
25
+ return nil if options.key?(:title) && !options[:title]
26
+ options[:title] || options[:type].to_s.titleize
27
+ end
28
+
29
+ def body_props
30
+ defaults = {
31
+ class: 'alert-body',
32
+ }
33
+ merge_props(from: defaults, to: options.dig(:props, :body))
34
+ end
35
+
36
+ def body_text
37
+ options[:body]
38
+ end
39
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ class BaseCell < Cell::ViewModel
4
+ view_paths << "#{File.dirname(__dir__)}/cells"
5
+
6
+ def c(*class_list)
7
+ class_list.flatten.compact.uniq.map(&:to_s).map(&:strip).join(' ').strip
8
+ end
9
+
10
+ def merge_props(from:, to:)
11
+ from ||= {}
12
+ to ||= {}
13
+ from = from.deep_symbolize_keys
14
+ to = to.deep_symbolize_keys
15
+ from.deep_merge(to) { |k, o, n| k == :class ? c(n, o) : n }
16
+ end
17
+
18
+ def renderable?(option)
19
+ options[option].respond_to?(:call)
20
+ end
21
+
22
+ def render_option(option)
23
+ return nil unless renderable?(option)
24
+ options[option].call
25
+ end
26
+
27
+ def render_attribute_path(path, object)
28
+ path&.to_s&.split('.')&.inject(object, :try)&.to_s
29
+ end
30
+
31
+ def fetch_errors(object, field)
32
+ field = field.to_s
33
+ return nil unless object.try(:errors)
34
+ errors = object.errors[field]
35
+ errors = object.errors[field.remove('_id')] unless errors.any?
36
+ return nil unless errors.any?
37
+ errors.join('; ')
38
+ end
39
+
40
+ def titleized_attribute_path(attribute)
41
+ attribute.to_s.split('.').map(&:titleize).join(' ')
42
+ end
43
+ end
@@ -0,0 +1,17 @@
1
+ <%= content_tag(tag, **button_props) do %>
2
+ <% if @options[:icon] %>
3
+ <%= content_tag(:span, class: 'flex justify-between items-center') do %>
4
+ <% if left_icon? %>
5
+ <%= content_tag(:i, nil, class: "fa fa-#{icon} mr-1") %>
6
+ <% end %>
7
+ <%= content_tag(:span, button_text) %>
8
+ <% if right_icon? %>
9
+ <%= content_tag(:i, nil, class: "fa fa-#{icon} ml-1") %>
10
+ <% end %>
11
+ <% end %>
12
+ <% else %>
13
+ <%= button_text %>
14
+ <% end %>
15
+
16
+ <%= append_text %>
17
+ <% end %>
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ButtonCell < BaseCell
4
+ private
5
+
6
+ def tag
7
+ options[:link] ? :a : :button
8
+ end
9
+
10
+ def button_props
11
+ defaults = {
12
+ class: 'btn btn-default',
13
+ (tag == :a ? :role : :type) => 'button',
14
+ }
15
+ defaults[:href] = options[:link] if tag == :a
16
+ merge_props(from: defaults, to: options.dig(:props, :button))
17
+ end
18
+
19
+ def button_text
20
+ options[:text]
21
+ end
22
+
23
+ def icon
24
+ return options[:icon] if options[:icon].is_a?(String)
25
+ return options.dig(:icon, :icon) if options[:icon].is_a?(Hash)
26
+ end
27
+
28
+ def left_icon?
29
+ return false unless options[:icon].is_a?(Hash)
30
+ options.dig(:icon, :justify).to_s == 'left'
31
+ end
32
+
33
+ def right_icon?
34
+ return true unless options[:icon].is_a?(Hash)
35
+ options.dig(:icon, :justify).to_s == 'right'
36
+ end
37
+
38
+ def append_text
39
+ options[:append]
40
+ end
41
+ end
@@ -0,0 +1,14 @@
1
+ <% if block_props.present? %>
2
+ <%= content_tag(:div, **block_props) do %>
3
+ <% if renderable?(:block) %>
4
+ <%= render_option(:block) %>
5
+ <% elsif block_text.is_a?(String) %>
6
+ <%= block_text %>
7
+ <% else %>
8
+ <%= render :block_title %>
9
+ <%= render :block_subtitle %>
10
+ <%= render :block_body %>
11
+ <%= render :block_text %>
12
+ <% end %>
13
+ <% end %>
14
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if block_body_props.present? %>
2
+ <%= content_tag(:div, **block_body_props) do %>
3
+ <%= block_body_text %>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if block_subtitle_props.present? %>
2
+ <%= content_tag(:h6, **block_subtitle_props) do %>
3
+ <%= block_subtitle_text %>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if block_text_props.present? %>
2
+ <%= content_tag(:div, **block_text_props) do %>
3
+ <%= block_text_text %>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <% if block_title_props.present? %>
2
+ <%= content_tag(:h3, **block_title_props) do %>
3
+ <%= block_title_text %>
4
+ <% end %>
5
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if footer_props.present? %>
2
+ <% if renderable?(:footer) %>
3
+ <%= render_option(:footer) %>
4
+ <% else %>
5
+ <%= content_tag(:div, **footer_props) do %>
6
+ <%= footer_text %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if header_props.present? %>
2
+ <% if renderable?(:header) %>
3
+ <%= render_option(:header) %>
4
+ <% else %>
5
+ <%= content_tag(:div, **header_props) do %>
6
+ <%= header_text %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if img_bottom_props.present? %>
2
+ <% if renderable?(:img_bottom) %>
3
+ <%= render_option(:img_bottom) %>
4
+ <% else %>
5
+ <%= content_tag(:div, **img_bottom_props) do %>
6
+ <%= img_bottom_text %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if img_top_props.present? %>
2
+ <% if renderable?(:img_top) %>
3
+ <%= render_option(:img_top) %>
4
+ <% else %>
5
+ <%= content_tag(:div, **img_top_props) do %>
6
+ <%= img_top_text %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if list_group_props.present? %>
2
+ <% if renderable?(:list_group) %>
3
+ <%= render_option(:list_group) %>
4
+ <% else %>
5
+ <%= content_tag(:div, **list_group_props) do %>
6
+ <%= list_group_text %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <%= content_tag(:div, **card_props) do %>
2
+ <%= render :img_top %>
3
+ <%= render :header %>
4
+ <%= render :block %>
5
+ <%= render :table %>
6
+ <%= render :list_group %>
7
+ <%= render :footer %>
8
+ <%= render :img_bottom %>
9
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if table_props.present? %>
2
+ <% if renderable?(:table) %>
3
+ <%= render_option(:table) %>
4
+ <% else %>
5
+ <%= content_tag(:div, **table_props) do %>
6
+ <%= table_text %>
7
+ <% end %>
8
+ <% end %>
9
+ <% end %>
@@ -0,0 +1,152 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CardCell < BaseCell
4
+ private
5
+
6
+ def card_props
7
+ defaults = {
8
+ class: 'card',
9
+ }
10
+ merge_props(from: defaults, to: options.dig(:props, :card))
11
+ end
12
+
13
+ def img_top_props
14
+ return nil unless options[:img_top] || options.dig(:props, :img_top)
15
+ defaults = {
16
+ class: 'card-img-top',
17
+ }
18
+ merge_props(from: defaults, to: options.dig(:props, :img_top))
19
+ end
20
+
21
+ def img_top_text
22
+ options[:img_top]
23
+ end
24
+
25
+ def header_props
26
+ return nil unless options[:header] || options.dig(:props, :header)
27
+ defaults = {
28
+ class: 'card-header',
29
+ }
30
+ merge_props(from: defaults, to: options.dig(:props, :header))
31
+ end
32
+
33
+ def header_text
34
+ options[:header]
35
+ end
36
+
37
+ def block_props
38
+ return nil unless options[:block] || options.dig(:props, :block)
39
+ defaults = {
40
+ class: 'card-block',
41
+ }
42
+ merge_props(from: defaults, to: options.dig(:props, :block)&.except(:title, :subtitle, :body, :text))
43
+ end
44
+
45
+ def block_text
46
+ options[:block]
47
+ end
48
+
49
+ def block_title_props
50
+ return nil unless options[:block].is_a?(Hash)
51
+ return nil unless options.dig(:block, :title) || options.dig(:props, :block, :title)
52
+ defaults = {
53
+ class: 'card-title',
54
+ }
55
+ merge_props(from: defaults, to: options.dig(:props, :block, :title))
56
+ end
57
+
58
+ def block_title_text
59
+ return nil unless options[:block].is_a? Hash
60
+ options.dig(:block, :title)
61
+ end
62
+
63
+ def block_subtitle_props
64
+ return nil unless options[:block].is_a?(Hash)
65
+ return nil unless options.dig(:block, :subtitle) || options.dig(:props, :block, :subtitle)
66
+ defaults = {
67
+ class: 'card-subtitle text-muted',
68
+ }
69
+ merge_props(from: defaults, to: options.dig(:props, :block, :subtitle))
70
+ end
71
+
72
+ def block_subtitle_text
73
+ return nil unless options[:block].is_a? Hash
74
+ options.dig(:block, :subtitle)
75
+ end
76
+
77
+ def block_text_props
78
+ return nil unless options[:block].is_a?(Hash)
79
+ return nil unless options.dig(:block, :text) || options.dig(:props, :block, :text)
80
+ defaults = {
81
+ class: 'card-text',
82
+ }
83
+ merge_props(from: defaults, to: options.dig(:props, :block, :text))
84
+ end
85
+
86
+ def block_text_text
87
+ return nil unless options[:block].is_a? Hash
88
+ options.dig(:block, :text)
89
+ end
90
+
91
+ def block_body_props
92
+ return nil unless options[:block].is_a?(Hash)
93
+ return nil unless options.dig(:block, :body) || options.dig(:props, :block, :body)
94
+ defaults = {
95
+ class: 'card-body',
96
+ }
97
+ merge_props(from: defaults, to: options.dig(:props, :block, :body))
98
+ end
99
+
100
+ def block_body_text
101
+ return nil unless options[:block].is_a? Hash
102
+ options.dig(:block, :body)
103
+ end
104
+
105
+ def table_props
106
+ return nil unless options[:table] || options.dig(:props, :table)
107
+ defaults = {
108
+ class: 'card-table',
109
+ }
110
+ merge_props(from: defaults, to: options.dig(:props, :table))
111
+ end
112
+
113
+ def table_text
114
+ options[:table]
115
+ end
116
+
117
+ def list_group_props
118
+ return nil unless options[:list_group] || options.dig(:props, :list_group)
119
+ defaults = {
120
+ class: 'card-list-group',
121
+ }
122
+ merge_props(from: defaults, to: options.dig(:props, :list_group))
123
+ end
124
+
125
+ def list_group_text
126
+ options[:list_group]
127
+ end
128
+
129
+ def footer_props
130
+ return nil unless options[:footer] || options.dig(:props, :footer)
131
+ defaults = {
132
+ class: 'card-footer',
133
+ }
134
+ merge_props(from: defaults, to: options.dig(:props, :footer))
135
+ end
136
+
137
+ def footer_text
138
+ options[:footer]
139
+ end
140
+
141
+ def img_bottom_props
142
+ return nil unless options[:img_bottom] || options.dig(:props, :img_bottom)
143
+ defaults = {
144
+ class: 'card-img-bottom',
145
+ }
146
+ merge_props(from: defaults, to: options.dig(:props, :img_bottom))
147
+ end
148
+
149
+ def img_bottom_text
150
+ options[:img_bottom]
151
+ end
152
+ end