From cceed6c6607166603cd5a23126ae6a085131977c Mon Sep 17 00:00:00 2001 From: YarekTenko Date: Fri, 10 Mar 2017 15:03:21 -0800 Subject: [PATCH 1/4] Update Rubocop Allow long strings for "context" --- .rubocop.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.rubocop.yml b/.rubocop.yml index 24ee097..5ec821f 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -23,3 +23,4 @@ Metrics/BlockLength: Metrics/LineLength: IgnoredPatterns: - '\w*it.+do' + - '\w*context.+do' From 6a369e09e5e555a7ea2f1397cc20fb3bb177920a Mon Sep 17 00:00:00 2001 From: YarekTenko Date: Tue, 7 Mar 2017 09:28:43 -0800 Subject: [PATCH 2/4] Add /lib folder to autoload_paths Adding pagination module that will have to be included in autoload_paths. --- config/application.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/config/application.rb b/config/application.rb index e15d607..58b21c8 100644 --- a/config/application.rb +++ b/config/application.rb @@ -11,5 +11,6 @@ class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. + config.autoload_paths << "#{Rails.root}/lib" end end From 27d2a5406712fb99e5e4a8803f0d9e80b1f79509 Mon Sep 17 00:00:00 2001 From: YarekTenko Date: Mon, 27 Mar 2017 10:07:28 -0700 Subject: [PATCH 3/4] Create Paginator module -Paginator module is responsible for calculating and rendering a pagination bar based on the passed parameters. -Added rspec for Paginator. --- lib/utilities/paginator.rb | 111 +++++++++++++++++++++++++++++++++ spec/modules/paginator_spec.rb | 93 +++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 lib/utilities/paginator.rb create mode 100644 spec/modules/paginator_spec.rb diff --git a/lib/utilities/paginator.rb b/lib/utilities/paginator.rb new file mode 100644 index 0000000..0cd3ab1 --- /dev/null +++ b/lib/utilities/paginator.rb @@ -0,0 +1,111 @@ +module Utilities + module Paginator + ELLIPSES = '...'.freeze + OFFSET = 1 + FIRST_PAGE = 1 + DIVIDER = 2 + + def items_to_display(model:, items_per_page: 5, current_page: 1) + @items_per_page = items_per_page + @current_page = current_page + @number_of_items = model.count + @last_page = (@number_of_items.to_f / @items_per_page).ceil + model.offset(items_per_page * (@current_page - OFFSET)) + .limit(items_per_page) + end + + def paginator(max_page_blocks: 7) + render partial: 'shared/paginator', + locals: { blocks: pages_to_display(@current_page, + max_page_blocks, + @last_page), + current_page: @current_page, + previous_link_css_class: previous_link_css_class, + next_link_css_class: next_link_css_class, + last_page: @last_page } + end + + def page_item_css_class(page, current_page) + if page == current_page + 'page-item active' + elsif page.to_s == ELLIPSES + 'page-item disabled' + end + end + + private + + def previous_link_css_class + @current_page == FIRST_PAGE ? 'page-item disabled' : 'page-item' + end + + def next_link_css_class + @current_page == @last_page ? 'page-item disabled' : 'page-item' + end + + def pages_to_display(current_page, max_page_blocks, number_of_pages) + if all_pages_fit?(number_of_pages, max_page_blocks) + complete_pagination(number_of_pages) + elsif current_page_at_the_beginning?(current_page, max_page_blocks) + beginning_pagination(max_page_blocks) + elsif current_page_at_the_end?(current_page, number_of_pages, + max_page_blocks) + end_pagination(max_page_blocks, number_of_pages) + else + general_pagination(current_page, max_page_blocks) + end + end + + def all_pages_fit?(number_of_pages, max_page_blocks) + number_of_pages < max_page_blocks + end + + def current_page_at_the_beginning?(current_page, max_page_blocks) + current_page <= (max_page_blocks / DIVIDER) + end + + def current_page_at_the_end?(current_page, number_of_pages, max_page_blocks) + current_page > (number_of_pages - (max_page_blocks / DIVIDER)) + end + + def general_pagination(current_page, max_page_blocks) + if max_page_blocks == 1 + [current_page] + elsif max_page_blocks == 2 + [current_page, ELLIPSES] + elsif max_page_blocks.odd? + odd_pages(current_page, max_page_blocks) + else + even_pages(current_page, max_page_blocks) + end + end + + def beginning_pagination(max_page_blocks) + start = FIRST_PAGE + finish = max_page_blocks - OFFSET + [*(start..finish), ELLIPSES] + end + + def end_pagination(max_page_blocks, number_of_pages) + start = number_of_pages - max_page_blocks + OFFSET * 2 + finish = number_of_pages + [ELLIPSES, *(start..finish)] + end + + def complete_pagination(last_page) + [*FIRST_PAGE..last_page] + end + + def odd_pages(current_page, max_page_blocks) + start = (current_page - (max_page_blocks - OFFSET) / DIVIDER) + OFFSET + finish = (current_page + (max_page_blocks - OFFSET) / DIVIDER) - OFFSET + [ELLIPSES, *(start..finish), ELLIPSES] + end + + def even_pages(current_page, max_page_blocks) + start = (current_page - (max_page_blocks - OFFSET) / DIVIDER) + OFFSET + finish = (current_page + (max_page_blocks / DIVIDER)) - OFFSET + [ELLIPSES, *(start..finish), ELLIPSES] + end + end +end diff --git a/spec/modules/paginator_spec.rb b/spec/modules/paginator_spec.rb new file mode 100644 index 0000000..4d0cc34 --- /dev/null +++ b/spec/modules/paginator_spec.rb @@ -0,0 +1,93 @@ +require 'rails_helper' + +RSpec.describe Utilities::Paginator, type: :module do + let!(:paginator) { Class.new { extend Utilities::Paginator } } + + describe('#pages_to_display') do + subject(:pages_to_display) do + paginator.send(:pages_to_display, + current_page, + maximum_page_blocks, + number_of_pages) + end + + context 'All pages fit within the pagination list' do + let(:maximum_page_blocks) { 7 } + let(:current_page) { 1 } + let(:number_of_pages) { 5 } + let(:expected_range_of_pages) { [1, 2, 3, 4, 5] } + + it 'displays correct range of pages' do + expect(pages_to_display).to eq expected_range_of_pages + end + end + + context 'Current page is in the beginning and there are more pages towards the end of the pagination list' do + let(:maximum_page_blocks) { 7 } + let(:current_page) { 3 } + let(:number_of_pages) { 11 } + let(:expected_range_of_pages) { [1, 2, 3, 4, 5, 6, '...'] } + + it 'displays correct range of pages' do + expect(pages_to_display).to eq expected_range_of_pages + end + end + + context 'Current page is at the end and there are more pages towards the beginning of the pagination list' do + let(:maximum_page_blocks) { 7 } + let(:current_page) { 9 } + let(:number_of_pages) { 11 } + let(:expected_range_of_pages) { ['...', 6, 7, 8, 9, 10, 11] } + + it 'displays correct range of pages' do + expect(pages_to_display).to eq expected_range_of_pages + end + end + + context 'Current page is in the middle and there are more pages towards the beginning and the end of the pagination list' do + context 'Maximum number of page blocks is 1' do + let(:maximum_page_blocks) { 1 } + let(:current_page) { 5 } + let(:number_of_pages) { 11 } + let(:expected_range_of_pages) { [5] } + + it 'displays correct range of pages' do + expect(pages_to_display).to eq expected_range_of_pages + end + end + + context 'Maximum number of page blocks is 2' do + let(:maximum_page_blocks) { 2 } + let(:current_page) { 6 } + let(:number_of_pages) { 11 } + let(:expected_range_of_pages) { [6, '...'] } + + it 'displays correct range of pages' do + expect(pages_to_display).to eq expected_range_of_pages + end + end + + context 'Maximum number of page blocks is odd' do + let(:maximum_page_blocks) { 7 } + let(:current_page) { 5 } + let(:number_of_pages) { 11 } + let(:expected_range_of_pages) { ['...', 3, 4, 5, 6, 7, '...'] } + + it 'displays correct range of pages' do + expect(pages_to_display).to eq expected_range_of_pages + end + end + + context 'Maximum number of page blocks is even' do + let(:maximum_page_blocks) { 6 } + let(:current_page) { 5 } + let(:number_of_pages) { 11 } + let(:expected_range_of_pages) { ['...', 4, 5, 6, 7, '...'] } + + it 'displays correct range of pages' do + expect(pages_to_display).to eq expected_range_of_pages + end + end + end + end +end From a9f2557c8d6e9d17316734ae481790fe77f6cdfc Mon Sep 17 00:00:00 2001 From: YarekTenko Date: Mon, 27 Mar 2017 10:08:19 -0700 Subject: [PATCH 4/4] Add views for Paginator module -Add _blocks.html.erb view that renders page blocks; -Add _paginator.html.erb view that renders the pagination panel for the current page of a given Model. --- app/views/shared/_blocks.html.erb | 5 ++++ app/views/shared/_paginator.html.erb | 38 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 app/views/shared/_blocks.html.erb create mode 100644 app/views/shared/_paginator.html.erb diff --git a/app/views/shared/_blocks.html.erb b/app/views/shared/_blocks.html.erb new file mode 100644 index 0000000..530ac74 --- /dev/null +++ b/app/views/shared/_blocks.html.erb @@ -0,0 +1,5 @@ +<%= + content_tag :li, class: page_item_css_class do + link_to page, bets_path(page: page), class: 'page-link' + end +%> diff --git a/app/views/shared/_paginator.html.erb b/app/views/shared/_paginator.html.erb new file mode 100644 index 0000000..842f295 --- /dev/null +++ b/app/views/shared/_paginator.html.erb @@ -0,0 +1,38 @@ +
+
    + <%= + content_tag :li, class: previous_link_css_class do + link_to bets_path(page: '1'), class: 'page-link' do + content_tag :i, nil, class: 'fa fa-angle-double-left' + end + end + %> + <%= + content_tag :li, class: previous_link_css_class do + link_to bets_path(page: current_page - 1), class: 'page-link' do + content_tag :i, nil, class: 'fa fa-angle-left' + end + end + %> + + <% blocks.each do |page|%> + <%= render 'shared/blocks', page: page, + page_item_css_class: page_item_css_class(page, current_page) %> + <% end %> + + <%= + content_tag :li, class: next_link_css_class do + link_to bets_path(page: current_page + 1), class: 'page-link' do + content_tag :i, nil, class: 'fa fa-angle-right' + end + end + %> + <%= + content_tag :li, class: next_link_css_class do + link_to bets_path(page: last_page), class: 'page-link' do + content_tag :i, nil, class: 'fa fa-angle-double-right' + end + end + %> +
+