bootstrap-cells 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.gitlab-ci.yml +13 -0
- data/.rspec +2 -0
- data/.rubocop.yml +27 -0
- data/CHANGELOG +29 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +200 -0
- data/Rakefile +8 -0
- data/app/assets/javascripts/bootstrap-cells/add_many_event_listeners.js +11 -0
- data/app/assets/javascripts/bootstrap-cells/index.js +3 -0
- data/app/assets/stylesheets/_bootstrap-cells.scss +7 -0
- data/app/views/kaminari/bootstrap/_first_page.html.erb +15 -0
- data/app/views/kaminari/bootstrap/_gap.html.erb +12 -0
- data/app/views/kaminari/bootstrap/_last_page.html.erb +16 -0
- data/app/views/kaminari/bootstrap/_next_page.html.erb +16 -0
- data/app/views/kaminari/bootstrap/_page.html.erb +17 -0
- data/app/views/kaminari/bootstrap/_paginator.html.erb +32 -0
- data/app/views/kaminari/bootstrap/_prev_page.html.erb +16 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bootstrap-cells.gemspec +36 -0
- data/lib/bootstrap-cells.rb +16 -0
- data/lib/bootstrap-cells/cells/alert/body.erb +7 -0
- data/lib/bootstrap-cells/cells/alert/show.erb +7 -0
- data/lib/bootstrap-cells/cells/alert/title.erb +9 -0
- data/lib/bootstrap-cells/cells/alert_cell.rb +39 -0
- data/lib/bootstrap-cells/cells/base_cell.rb +43 -0
- data/lib/bootstrap-cells/cells/button/show.erb +17 -0
- data/lib/bootstrap-cells/cells/button_cell.rb +41 -0
- data/lib/bootstrap-cells/cells/card/block.erb +14 -0
- data/lib/bootstrap-cells/cells/card/block_body.erb +5 -0
- data/lib/bootstrap-cells/cells/card/block_subtitle.erb +5 -0
- data/lib/bootstrap-cells/cells/card/block_text.erb +5 -0
- data/lib/bootstrap-cells/cells/card/block_title.erb +5 -0
- data/lib/bootstrap-cells/cells/card/footer.erb +9 -0
- data/lib/bootstrap-cells/cells/card/header.erb +9 -0
- data/lib/bootstrap-cells/cells/card/img_bottom.erb +9 -0
- data/lib/bootstrap-cells/cells/card/img_top.erb +9 -0
- data/lib/bootstrap-cells/cells/card/list_group.erb +9 -0
- data/lib/bootstrap-cells/cells/card/show.erb +9 -0
- data/lib/bootstrap-cells/cells/card/table.erb +9 -0
- data/lib/bootstrap-cells/cells/card_cell.rb +152 -0
- data/lib/bootstrap-cells/cells/column/td.erb +1 -0
- data/lib/bootstrap-cells/cells/column/th.erb +9 -0
- data/lib/bootstrap-cells/cells/column_cell.rb +49 -0
- data/lib/bootstrap-cells/cells/field/required_field.scss +5 -0
- data/lib/bootstrap-cells/cells/field/show.erb +15 -0
- data/lib/bootstrap-cells/cells/field_cell.rb +96 -0
- data/lib/bootstrap-cells/cells/fields_for/form.scss +12 -0
- data/lib/bootstrap-cells/cells/fields_for/form_horizontal.scss +33 -0
- data/lib/bootstrap-cells/cells/fields_for/show.erb +3 -0
- data/lib/bootstrap-cells/cells/fields_for_cell.rb +15 -0
- data/lib/bootstrap-cells/cells/kv_horizontal/show.erb +17 -0
- data/lib/bootstrap-cells/cells/kv_horizontal_cell.rb +34 -0
- data/lib/bootstrap-cells/cells/kv_vertical/show.erb +17 -0
- data/lib/bootstrap-cells/cells/kv_vertical_cell.rb +32 -0
- data/lib/bootstrap-cells/cells/modal/body.erb +9 -0
- data/lib/bootstrap-cells/cells/modal/button.erb +9 -0
- data/lib/bootstrap-cells/cells/modal/content.erb +12 -0
- data/lib/bootstrap-cells/cells/modal/footer.erb +10 -0
- data/lib/bootstrap-cells/cells/modal/header.erb +12 -0
- data/lib/bootstrap-cells/cells/modal/modal.js +15 -0
- data/lib/bootstrap-cells/cells/modal/show.erb +9 -0
- data/lib/bootstrap-cells/cells/modal_cell.rb +64 -0
- data/lib/bootstrap-cells/cells/pages/pages.scss +4 -0
- data/lib/bootstrap-cells/cells/pages/show.erb +3 -0
- data/lib/bootstrap-cells/cells/pages_cell.rb +16 -0
- data/lib/bootstrap-cells/cells/table/nubbin.scss +40 -0
- data/lib/bootstrap-cells/cells/table/show.erb +7 -0
- data/lib/bootstrap-cells/cells/table/table_sort.scss +17 -0
- data/lib/bootstrap-cells/cells/table/table_striped_nested.scss +8 -0
- data/lib/bootstrap-cells/cells/table/tbody.erb +3 -0
- data/lib/bootstrap-cells/cells/table/tbody_button_for_nested_row.erb +9 -0
- data/lib/bootstrap-cells/cells/table/tbody_final_row.erb +9 -0
- data/lib/bootstrap-cells/cells/table/tbody_first_row.erb +9 -0
- data/lib/bootstrap-cells/cells/table/tbody_nested_row.erb +6 -0
- data/lib/bootstrap-cells/cells/table/tbody_rows.erb +35 -0
- data/lib/bootstrap-cells/cells/table/thead.erb +11 -0
- data/lib/bootstrap-cells/cells/table_cell.rb +68 -0
- data/lib/bootstrap-cells/cells/tabs/show.erb +19 -0
- data/lib/bootstrap-cells/cells/tabs_cell.rb +40 -0
- data/lib/bootstrap-cells/engine.rb +9 -0
- metadata +307 -0
@@ -0,0 +1 @@
|
|
1
|
+
<%= content_tag(:td, cell_text, **td_props) %>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ColumnCell < BaseCell
|
4
|
+
def th
|
5
|
+
render
|
6
|
+
end
|
7
|
+
|
8
|
+
def td
|
9
|
+
render
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def th_props
|
15
|
+
defaults = {
|
16
|
+
class: c(('sort' if options[:sort]),
|
17
|
+
("col-xs-#{options[:columns]}" if options[:columns]),
|
18
|
+
('text-center' if options[:center])),
|
19
|
+
data: { sort: options[:attribute] },
|
20
|
+
}
|
21
|
+
merge_props(from: defaults, to: options.dig(:props, :th))
|
22
|
+
end
|
23
|
+
|
24
|
+
def td_props
|
25
|
+
defaults = {
|
26
|
+
class: c(options[:attribute],
|
27
|
+
('truncate' if options[:truncate]),
|
28
|
+
('text-center' if options[:center])),
|
29
|
+
}
|
30
|
+
merge_props(from: defaults, to: options.dig(:props, :td))
|
31
|
+
end
|
32
|
+
|
33
|
+
def header_text
|
34
|
+
return options[:header] if options[:header]
|
35
|
+
return nil unless options[:attribute]
|
36
|
+
return options[:model].human_attribute_name(
|
37
|
+
options[:attribute],
|
38
|
+
default: I18n.t(options[:attribute],
|
39
|
+
scope: :attributes,
|
40
|
+
default: titleized_attribute_path(options[:attribute]))
|
41
|
+
) if options[:model].respond_to?(:human_attribute_name)
|
42
|
+
titleized_attribute_path(options[:attribute])
|
43
|
+
end
|
44
|
+
|
45
|
+
def cell_text
|
46
|
+
return '—' unless options[:cell] || options[:attribute]
|
47
|
+
options[:cell]&.call(model, options[:index]) || render_attribute_path(options[:attribute], model)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<% if field[:hidden] %>
|
2
|
+
<%= hidden_field(field_input_name, field_input_attribute, value: field_input_value) %>
|
3
|
+
<% else %>
|
4
|
+
<%= content_tag(:div, **container_props) do %>
|
5
|
+
<% unless field[:label] == false %>
|
6
|
+
<%= content_tag(:label, label_text, **label_props) %>
|
7
|
+
<% end %>
|
8
|
+
<%= content_tag(:div, **value_props) do %>
|
9
|
+
<%= value_text %>
|
10
|
+
<% end %>
|
11
|
+
<% if field[:errors] && field[:errors].present? %>
|
12
|
+
<span class="help-block"><%= field[:errors] %></span>
|
13
|
+
<% end %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class FieldCell < BaseCell
|
4
|
+
private
|
5
|
+
|
6
|
+
def field
|
7
|
+
@field ||= field_props
|
8
|
+
end
|
9
|
+
|
10
|
+
def field_props
|
11
|
+
attribute = @options[:attribute]
|
12
|
+
defaults = {
|
13
|
+
attribute: attribute,
|
14
|
+
required: false,
|
15
|
+
hidden: false,
|
16
|
+
readonly: false,
|
17
|
+
props: {
|
18
|
+
container: {},
|
19
|
+
label: {},
|
20
|
+
value: {},
|
21
|
+
input: {},
|
22
|
+
},
|
23
|
+
}
|
24
|
+
|
25
|
+
params = merge_props(from: defaults, to: @options)
|
26
|
+
params[:required] = 'required' if params[:required]
|
27
|
+
params[:errors] ||= fetch_errors(model, attribute) if model
|
28
|
+
params
|
29
|
+
end
|
30
|
+
|
31
|
+
def attribute
|
32
|
+
field[:attribute].to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def container_props
|
36
|
+
defaults = {
|
37
|
+
class: %w[form-group px-0],
|
38
|
+
}
|
39
|
+
defaults[:class] << %w[has-error] if field[:errors]
|
40
|
+
defaults[:class] << %w[required] if field[:required]
|
41
|
+
merge_props(from: defaults, to: field.dig(:props, :container))
|
42
|
+
end
|
43
|
+
|
44
|
+
def label_props
|
45
|
+
defaults = {
|
46
|
+
class: %w[control-label],
|
47
|
+
}
|
48
|
+
merge_props(from: defaults, to: field.dig(:props, :label))
|
49
|
+
end
|
50
|
+
|
51
|
+
def label_text
|
52
|
+
return field[:label] if field[:label].is_a?(String)
|
53
|
+
return nil if field[:label] == false || !model
|
54
|
+
return model.class.human_attribute_name(
|
55
|
+
attribute,
|
56
|
+
default: I18n.t(attribute,
|
57
|
+
scope: :attributes,
|
58
|
+
default: titleized_attribute_path(attribute))
|
59
|
+
) if model.class.respond_to?(:human_attribute_name)
|
60
|
+
titleized_attribute_path(attribute)
|
61
|
+
end
|
62
|
+
|
63
|
+
def value_props
|
64
|
+
defaults = {
|
65
|
+
class: %w[control-value],
|
66
|
+
}
|
67
|
+
defaults[:class] << %w[form-control-static] if field[:readonly]
|
68
|
+
merge_props(from: defaults, to: field.dig(:props, :value))
|
69
|
+
end
|
70
|
+
|
71
|
+
def value_text
|
72
|
+
return field[:output] if field[:output]
|
73
|
+
return render_attribute_path(attribute, model) if field[:readonly]
|
74
|
+
text_field(field_input_name,
|
75
|
+
field_input_attribute,
|
76
|
+
value: field_input_value,
|
77
|
+
class: c(field.dig(:props, :input, :class), 'form-control px-2'),
|
78
|
+
placeholder: field[:placeholder] || titleized_attribute_path(attribute),
|
79
|
+
**field.dig(:props, :input).except(:class))
|
80
|
+
end
|
81
|
+
|
82
|
+
def field_input_name
|
83
|
+
return nil unless model
|
84
|
+
param_name = (model.try(:model_name) || model.class.name.remove('Filterer').constantize.new.model_name)&.param_key
|
85
|
+
param_name.to_s + attribute.split('.')[0..-2].map { |a| '[' + a + ']' }.join
|
86
|
+
end
|
87
|
+
|
88
|
+
def field_input_attribute
|
89
|
+
attribute.split('.').last
|
90
|
+
end
|
91
|
+
|
92
|
+
def field_input_value
|
93
|
+
return field[:output] if field[:output]
|
94
|
+
render_attribute_path(attribute, model)
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
.form-horizontal {
|
2
|
+
.form-group {
|
3
|
+
display: flex;
|
4
|
+
flex-wrap: wrap;
|
5
|
+
align-items: center;
|
6
|
+
margin-left: 0;
|
7
|
+
margin-right: 0;
|
8
|
+
|
9
|
+
.control-label, .sr-only {
|
10
|
+
flex-basis: 20%;
|
11
|
+
width: 20%;
|
12
|
+
text-align: right;
|
13
|
+
padding: 0;
|
14
|
+
}
|
15
|
+
> .control-value,
|
16
|
+
> .help-block {
|
17
|
+
flex-basis: 75%;
|
18
|
+
width: 75%;
|
19
|
+
margin-left: 2%;
|
20
|
+
}
|
21
|
+
> .control-value:only-child {
|
22
|
+
flex-basis: 100%;
|
23
|
+
width: 100%;
|
24
|
+
margin-left: 0;
|
25
|
+
}
|
26
|
+
.sr-only + .control-value {
|
27
|
+
margin-left: 22%;
|
28
|
+
}
|
29
|
+
> .help-block {
|
30
|
+
margin-left: 22%;
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bootstrap-cells/cells/field_cell'
|
4
|
+
|
5
|
+
class FieldsForCell < BaseCell
|
6
|
+
private
|
7
|
+
|
8
|
+
def fields
|
9
|
+
(options[:fields] || []).compact
|
10
|
+
end
|
11
|
+
|
12
|
+
def options_for(field:)
|
13
|
+
options.slice(:required, :hidden, :readonly).merge(field)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%= content_tag(:dl, **item_props) do %>
|
2
|
+
<%= content_tag(:dt, **key_props) do %>
|
3
|
+
<% if renderable?(:key) %>
|
4
|
+
<%= render_option(:key) %>
|
5
|
+
<% else %>
|
6
|
+
<%= key_text %>
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<%= content_tag(:dd, **value_props) do %>
|
11
|
+
<% if renderable?(:value) %>
|
12
|
+
<%= render_option(:value) %>
|
13
|
+
<% else %>
|
14
|
+
<%= value_text %>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class KvHorizontalCell < BaseCell
|
4
|
+
private
|
5
|
+
|
6
|
+
def item_props
|
7
|
+
defaults = {
|
8
|
+
class: 'col-xs-12 my-0 mr-auto',
|
9
|
+
}
|
10
|
+
merge_props(from: defaults, to: options.dig(:props, :item))
|
11
|
+
end
|
12
|
+
|
13
|
+
def key_props
|
14
|
+
defaults = {
|
15
|
+
class: 'col-xs-3 right-align pr-2',
|
16
|
+
}
|
17
|
+
merge_props(from: defaults, to: options.dig(:props, :key))
|
18
|
+
end
|
19
|
+
|
20
|
+
def key_text
|
21
|
+
options[:key]
|
22
|
+
end
|
23
|
+
|
24
|
+
def value_props
|
25
|
+
defaults = {
|
26
|
+
class: 'col-xs-9',
|
27
|
+
}
|
28
|
+
merge_props(from: defaults, to: options.dig(:props, :value))
|
29
|
+
end
|
30
|
+
|
31
|
+
def value_text
|
32
|
+
options[:value] || '—'
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<%= content_tag(:dl, **item_props) do %>
|
2
|
+
<%= content_tag(:dt, **key_props) do %>
|
3
|
+
<% if renderable?(:key) %>
|
4
|
+
<%= render_option(:key) %>
|
5
|
+
<% else %>
|
6
|
+
<%= key_text %>
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
<%= content_tag(:dd, **value_props) do %>
|
11
|
+
<% if renderable?(:value) %>
|
12
|
+
<%= render_option(:value) %>
|
13
|
+
<% else %>
|
14
|
+
<%= value_text %>
|
15
|
+
<% end %>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class KvVerticalCell < BaseCell
|
4
|
+
private
|
5
|
+
|
6
|
+
def item_props
|
7
|
+
defaults = {
|
8
|
+
class: 'my-0',
|
9
|
+
}
|
10
|
+
merge_props(from: defaults, to: options.dig(:props, :item))
|
11
|
+
end
|
12
|
+
|
13
|
+
def key_props
|
14
|
+
defaults = {
|
15
|
+
}
|
16
|
+
merge_props(from: defaults, to: options.dig(:props, :key))
|
17
|
+
end
|
18
|
+
|
19
|
+
def key_text
|
20
|
+
options[:key]
|
21
|
+
end
|
22
|
+
|
23
|
+
def value_props
|
24
|
+
defaults = {
|
25
|
+
}
|
26
|
+
merge_props(from: defaults, to: options.dig(:props, :value))
|
27
|
+
end
|
28
|
+
|
29
|
+
def value_text
|
30
|
+
options[:value] || '—'
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="modal-content">
|
2
|
+
<%= render :header %>
|
3
|
+
|
4
|
+
<% if renderable?(:content) %>
|
5
|
+
<%= render_option(:content) %>
|
6
|
+
<% else %>
|
7
|
+
<%= content_tag(:div, **content_props) do %>
|
8
|
+
<%= render :body %>
|
9
|
+
<%= render :footer %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
12
|
+
</div>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<div class="modal-footer">
|
2
|
+
<% if renderable?(:footer) %>
|
3
|
+
<%= render_option(:footer) %>
|
4
|
+
<% else %>
|
5
|
+
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
6
|
+
<%= content_tag(:span, **footer_props) do %>
|
7
|
+
<%= footer_text %>
|
8
|
+
<% end %>
|
9
|
+
<% end %>
|
10
|
+
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<div class="modal-header">
|
2
|
+
<% if renderable?(:header) %>
|
3
|
+
<%= render_option(:header) %>
|
4
|
+
<% else %>
|
5
|
+
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
6
|
+
<span aria-hidden="true">×</span>
|
7
|
+
</button>
|
8
|
+
<%= content_tag(header_props[:tag], **header_props.except(:tag)) do %>
|
9
|
+
<%= header_text %>
|
10
|
+
<% end %>
|
11
|
+
<% end %>
|
12
|
+
</div>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
var handleModals = function handleModals() {
|
2
|
+
document.querySelectorAll('.bootstrap-modal [data-toggle="modal"]').forEach(function(modalButton) {
|
3
|
+
var modal = modalButton.parentNode.querySelector('.modal');
|
4
|
+
var randomId = Math.random().toString().substr(-10);
|
5
|
+
|
6
|
+
modal.setAttribute('id', randomId);
|
7
|
+
modalButton.setAttribute('data-target', '#' + randomId);
|
8
|
+
|
9
|
+
document.querySelector('body').appendChild( modal )
|
10
|
+
});
|
11
|
+
}
|
12
|
+
|
13
|
+
addManyEventListeners(document,
|
14
|
+
"page:change turbolinks:load ajax:complete",
|
15
|
+
handleModals);
|