Skip to content

Commit

Permalink
Add config.horizontal_scroll_list to enable horizontal scrolling colu…
Browse files Browse the repository at this point in the history
…mns and frozen row headers instead of paginated sets

Addresses Issue railsadminteam#2272.
  • Loading branch information
sbull committed May 1, 2018
1 parent e4c657f commit a03b4b4
Show file tree
Hide file tree
Showing 3 changed files with 202 additions and 34 deletions.
123 changes: 89 additions & 34 deletions app/views/rails_admin/main/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,22 @@
properties = @model_config.list.with(controller: self.controller, view: self, object: @abstract_model.model.new).visible_fields
checkboxes = @model_config.list.checkboxes?
# columns paginate
sets = get_column_sets(properties)
properties = sets[params[:set].to_i] || []
other_left = ((params[:set].to_i - 1) >= 0) && sets[params[:set].to_i - 1].present?
other_right = sets[params[:set].to_i + 1].present?
horiz_scroll_config = RailsAdmin::Config.horizontal_scroll_list
horiz_scroll_enabled = !!horiz_scroll_config
if horiz_scroll_enabled
if horiz_scroll_config.is_a?(Hash)
horiz_scroll_frozen_cols = horiz_scroll_config[:num_frozen_columns]
horiz_scroll_css = horiz_scroll_config[:css]
end
horiz_scroll_frozen_cols ||= 3 # by default, freeze checkboxes, links & first property (usually id?)
horiz_scroll_frozen_cols -= 1 unless checkboxes
else
horiz_scroll_frozen_cols = 0
sets = get_column_sets(properties)
properties = sets[params[:set].to_i] || []
other_left = ((params[:set].to_i - 1) >= 0) && sets[params[:set].to_i - 1].present?
other_right = sets[params[:set].to_i + 1].present?
end

- content_for :contextual_tabs do
- if checkboxes
Expand All @@ -39,11 +51,43 @@
jQuery(function($) {
#{ordered_filter_string}
});
- if horiz_scroll_enabled && horiz_scroll_frozen_cols > 0
:javascript
(function(){
if (window.rails_admin_horizontal_scroll_list) { return; } // Don't add this handler multiple times.
window.rails_admin_horizontal_scroll_list = true;
var $ = jQuery;
var setFrozenColPositions = function(){
var firstPosition, $td;
$('#bulk_form').find('table tr').each(function(index, tr){
$(tr).find('.scroll-frozen').each(function(idx, td){
$td = $(td);
if (idx === 0) {
firstPosition = $td.position().left;
}
td.style.left = ($td.position().left-firstPosition)+'px';
});
});
};
$(window).on('load', setFrozenColPositions); // Update after link icons load.
$(document).on('rails_admin.dom_ready', setFrozenColPositions);
}());
%style
- properties.select{ |p| p.column_width.present? }.each do |property|
= "#list th.#{property.css_class} { width: #{property.column_width}px; min-width: #{property.column_width}px; }"
= "#list td.#{property.css_class} { max-width: #{property.column_width}px; }"
- if horiz_scroll_enabled
\.table-wrapper { margin-bottom: 20px; overflow-x: auto; }
\.table-wrapper .table { margin-bottom: 0; }
- if horiz_scroll_frozen_cols > 0
\/* Remove transparency on frozen cells. */
\.table-striped > tbody > tr:nth-child(even) > td.scroll-frozen, .table-striped > thead > tr > th.scroll-frozen { background-color: #fff; }
body.rails_admin .table .headerSortUp.scroll-frozen, body.rails_admin .table .headerSortDown.scroll-frozen { background-color: #e2eff6; }
\.scroll-frozen { position: sticky; }
\.scroll-frozen-last { box-shadow: -1px 0 0 0 #ddd inset; } /* border-right isn't sticky */
\.table-condensed th.scroll-frozen-last, .table-condensed td.scroll-frozen-last { padding-right: 6px; }
= horiz_scroll_css

#list
= form_tag(index_path(params.except(*%w[page f query])), method: :get, class: "pjax-form form-inline") do
Expand Down Expand Up @@ -74,37 +118,48 @@
%p
%strong= description

%table.table.table-condensed.table-striped
%thead
%tr
- if checkboxes
%th.shrink
%input.toggle{type: "checkbox"}
- if other_left
%th.other.left.shrink= "..."
- properties.each do |property|
- selected = (sort == property.name.to_s)
- if property.sortable
- sort_location = index_path params.except('sort_reverse').except('page').merge(sort: property.name).merge(selected && sort_reverse != "true" ? {sort_reverse: "true"} : {})
- sort_direction = (sort_reverse == 'true' ? "headerSortUp" : "headerSortDown" if selected)
%th{class: "#{property.sortable && "header pjax" || nil} #{sort_direction if property.sortable && sort_direction} #{property.css_class} #{property.type_css_class}", :'data-href' => (property.sortable && sort_location), rel: "tooltip", title: "#{property.hint}"}= capitalize_first_letter(property.label)
- if other_right
%th.other.right.shrink= "..."
%th.last.shrink
%tbody
- @objects.each do |object|
%tr{class: "#{@abstract_model.param_key}_row #{@model_config.list.with(object: object).row_css_class}"}
.table-wrapper
%table.table.table-condensed.table-striped
%thead
%tr
- horiz_scroll_i = horiz_scroll_frozen_cols
- if checkboxes
%td= check_box_tag "bulk_ids[]", object.id, false
- if @other_left_link ||= other_left && index_path(params.except('set').merge(params[:set].to_i != 1 ? {set: (params[:set].to_i - 1)} : {}))
%td.other.left= link_to "...", @other_left_link, class: 'pjax'
- properties.map{ |property| property.bind(:object, object) }.each do |property|
- value = property.pretty_value
%td{class: "#{property.css_class} #{property.type_css_class}", title: strip_tags(value.to_s)}= value
- if @other_right_link ||= other_right && index_path(params.merge(set: (params[:set].to_i + 1)))
%td.other.right= link_to "...", @other_right_link, class: 'pjax'
%td.last.links
%ul.inline.list-inline= menu_for :member, @abstract_model, object, true
%th.shrink{class: [(horiz_scroll_i -= 1) > -1 && 'scroll-frozen', horiz_scroll_i == 0 && 'scroll-frozen-last']}
%input.toggle{type: "checkbox"}
- if horiz_scroll_enabled
%th.last.shrink{class: [(horiz_scroll_i -= 1) > -1 && 'scroll-frozen', horiz_scroll_i == 0 && 'scroll-frozen-last']}
- elsif other_left
%th.other.left.shrink= "..."
- properties.each do |property|
- selected = (sort == property.name.to_s)
- if property.sortable
- sort_location = index_path params.except('sort_reverse').except('page').merge(sort: property.name).merge(selected && sort_reverse != "true" ? {sort_reverse: "true"} : {})
- sort_direction = (sort_reverse == 'true' ? "headerSortUp" : "headerSortDown" if selected)
%th{class: [property.sortable && "header pjax", property.sortable && sort_direction, property.css_class, property.type_css_class, (horiz_scroll_i -= 1) > -1 && 'scroll-frozen', horiz_scroll_i == 0 && 'scroll-frozen-last'], :'data-href' => (property.sortable && sort_location), rel: "tooltip", title: "#{property.hint}"}= capitalize_first_letter(property.label)
- unless horiz_scroll_enabled
- if other_right
%th.other.right.shrink= "..."
%th.last.shrink
%tbody
- @objects.each do |object|
- horiz_scroll_i = horiz_scroll_frozen_cols
%tr{class: "#{@abstract_model.param_key}_row #{@model_config.list.with(object: object).row_css_class}"}
- if checkboxes
%td{class: [(horiz_scroll_i -= 1) > -1 && 'scroll-frozen', horiz_scroll_i == 0 && 'scroll-frozen-last']}= check_box_tag "bulk_ids[]", object.id, false
- td_links = capture do
%td.last.links{class: [(horiz_scroll_i -= 1) > -1 && 'scroll-frozen', horiz_scroll_i == 0 && 'scroll-frozen-last']}
%ul.inline.list-inline= menu_for :member, @abstract_model, object, true
- if horiz_scroll_enabled
= td_links
- elsif @other_left_link ||= other_left && index_path(params.except('set').merge(params[:set].to_i != 1 ? {set: (params[:set].to_i - 1)} : {}))
%td.other.left= link_to "...", @other_left_link, class: 'pjax'
- properties.map{ |property| property.bind(:object, object) }.each do |property|
- value = property.pretty_value
%td{class: [property.css_class, property.type_css_class, (horiz_scroll_i -= 1) > -1 && 'scroll-frozen', horiz_scroll_i == 0 && 'scroll-frozen-last' ], title: strip_tags(value.to_s)}= value
- unless horiz_scroll_enabled
- if @other_right_link ||= other_right && index_path(params.merge(set: (params[:set].to_i + 1)))
%td.other.right= link_to "...", @other_right_link, class: 'pjax'
= td_links

- if @model_config.list.limited_pagination
.row
Expand Down
4 changes: 4 additions & 0 deletions lib/rails_admin/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ class << self
# Set the max width of columns in list view before a new set is created
attr_accessor :total_columns_width

# Enable horizontal-scroll table in list view, ignore total_columns_width
attr_accessor :horizontal_scroll_list

# set parent controller
attr_accessor :parent_controller

Expand Down Expand Up @@ -285,6 +288,7 @@ def reset
@excluded_models = []
@included_models = []
@total_columns_width = 697
@horizontal_scroll_list = nil
@label_methods = [:name, :title]
@main_app_name = proc { [Rails.application.engine_name.titleize.chomp(' Application'), 'Admin'] }
@registry = {}
Expand Down
109 changes: 109 additions & 0 deletions spec/integration/config/list/rails_admin_config_list_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -474,4 +474,113 @@
end
end
end

describe 'horizontal-scroll list option' do
horiz_scroll_css = {
enabled: '.table-wrapper { margin-bottom: 20px; overflow-x: auto; }',
frozen_cols: '.scroll-frozen { position: sticky; }',
last_col: '.scroll-frozen-last { box-shadow: -1px 0 0 0 #ddd inset; }',
}
js_include_test = "td.style.left = ($td.position().left-firstPosition)+'px';"
all_team_columns = ['', '', 'Id', 'Created at', 'Updated at', 'Division', 'Name', 'Logo url', 'Team Manager', 'Ballpark', 'Mascot', 'Founded', 'Wins', 'Losses', 'Win percentage', 'Revenue', 'Color', 'Custom field', 'Main Sponsor', 'Players', 'Some Fans', 'Comments']

it "displays all fields with on one page when true" do
RailsAdmin.config do |config|
config.horizontal_scroll_list = true
end
FactoryGirl.create_list :team, 3
visit index_path(model_name: 'team')
cols = all('th').collect(&:text)
expect(cols[0..4]).to eq(all_team_columns[0..4])
expect(cols).to contain_exactly(*all_team_columns)
expect(page).to have_selector('.table-wrapper')
expect(page.html).to include(horiz_scroll_css[:enabled])
expect(page.html).to include(horiz_scroll_css[:frozen_cols])
expect(page.html).to include(horiz_scroll_css[:last_col])
expect(page.html).to include(js_include_test)
expect(all('.scroll-frozen').count).to eq(12)
expect(all('th.scroll-frozen').count).to eq(3)
expect(all('td.scroll-frozen').count).to eq(9)
expect(all('.scroll-frozen-last').count).to eq(4)
end

it "displays all fields with custom css" do
custom_css = '.scroll-frozen-last { box-shadow: none; }'
RailsAdmin.config do |config|
config.horizontal_scroll_list = {css: custom_css}
end
visit index_path(model_name: 'team')
cols = all('th').collect(&:text)
expect(cols[0..4]).to eq(all_team_columns[0..4])
expect(cols).to contain_exactly(*all_team_columns)
expect(page.html).to include(horiz_scroll_css[:enabled])
expect(page.html).to include(horiz_scroll_css[:frozen_cols])
expect(page.html).to include(custom_css)
expect(page.html).to include(js_include_test)
end

it "displays all fields with custom frozen columns" do
RailsAdmin.config do |config|
config.horizontal_scroll_list = {num_frozen_columns: 2}
end
FactoryGirl.create_list :team, 3
visit index_path(model_name: 'team')
cols = all('th').collect(&:text)
expect(cols[0..4]).to eq(all_team_columns[0..4])
expect(cols).to contain_exactly(*all_team_columns)
expect(page.html).to include(horiz_scroll_css[:enabled])
expect(page.html).to include(horiz_scroll_css[:frozen_cols])
expect(page.html).to include(horiz_scroll_css[:last_col])
expect(page.html).to include(js_include_test)
expect(all('.scroll-frozen').count).to eq(8)
expect(all('th.scroll-frozen').count).to eq(2)
expect(all('td.scroll-frozen').count).to eq(6)
expect(all('.scroll-frozen-last').count).to eq(4)
end

it "displays all fields with no checkboxes" do
RailsAdmin.config do |config|
config.horizontal_scroll_list = true
end
RailsAdmin.config Team do
list do
checkboxes false
end
end
FactoryGirl.create_list :team, 3
visit index_path(model_name: 'team')
cols = all('th').collect(&:text)
expect(cols[0..3]).to eq(all_team_columns[1..4])
expect(cols).to contain_exactly(*all_team_columns[1..-1])
expect(all('.scroll-frozen').count).to eq(8)
expect(all('th.scroll-frozen').count).to eq(2)
expect(all('td.scroll-frozen').count).to eq(6)
expect(all('.scroll-frozen-last').count).to eq(4)
end

it "displays all fields with no frozen columns" do
RailsAdmin.config do |config|
config.horizontal_scroll_list = {num_frozen_columns: 0}
end
FactoryGirl.create_list :team, 3
visit index_path(model_name: 'team')
cols = all('th').collect(&:text)
expect(cols[0..4]).to eq(all_team_columns[0..4])
expect(cols).to contain_exactly(*all_team_columns)
expect(page.html).to include(horiz_scroll_css[:enabled])
expect(page.html).not_to include(horiz_scroll_css[:frozen_cols])
expect(page.html).not_to include(js_include_test)
expect(all('.scroll-frozen').count).to eq(0)
expect(all('.scroll-frozen-last').count).to eq(0)
end

it "displays sets when not set" do
visit index_path(model_name: 'team')
expect(all('th').collect(&:text)).to eq ['', 'Id', 'Created at', 'Updated at', 'Division', 'Name', 'Logo url', '...', '']
expect(page.html).not_to include(horiz_scroll_css[:enabled])
expect(page.html).not_to include(horiz_scroll_css[:frozen_cols])
expect(page.html).not_to include(horiz_scroll_css[:last_col])
expect(page.html).not_to include(js_include_test)
end
end
end

0 comments on commit a03b4b4

Please sign in to comment.