From 9e18e6f2518bb71307b34bd150b208820c134904 Mon Sep 17 00:00:00 2001 From: Anton Khorev Date: Wed, 25 Jun 2025 19:49:07 +0300 Subject: [PATCH] Add links to versions with a fixed step The idea is to make every version accessible in two clicks. --- app/helpers/numbered_pagination_helper.rb | 27 ++++-- .../numbered_pagination_helper_test.rb | 94 +++++++++++++++++++ 2 files changed, 112 insertions(+), 9 deletions(-) diff --git a/app/helpers/numbered_pagination_helper.rb b/app/helpers/numbered_pagination_helper.rb index af3c684e9..043385c6b 100644 --- a/app/helpers/numbered_pagination_helper.rb +++ b/app/helpers/numbered_pagination_helper.rb @@ -1,5 +1,5 @@ module NumberedPaginationHelper - def element_versions_pagination(top_version, active_version: top_version + 1, window_half_size: 50, &) + def element_versions_pagination(top_version, active_version: top_version + 1, window_half_size: 50, step_size: 50, &) lists = [] if top_version <= 5 @@ -11,8 +11,16 @@ module NumberedPaginationHelper else start_list_versions = 1..(active_version < 3 ? active_version + 1 : 1) end_list_versions = (active_version > top_version - 2 ? active_version - 1 : top_version)..top_version - middle_list_versions = Range.new([active_version - window_half_size, start_list_versions.last + 1].max, - [active_version + window_half_size, end_list_versions.first - 1].min) + + middle_list_version_sentinels = [start_list_versions.last, end_list_versions.first] + middle_list_version_steps = Range.new(*middle_list_version_sentinels).filter { |v| (v % step_size).zero? } + middle_list_version_window = Range.new([active_version - window_half_size, start_list_versions.last].max, + [active_version + window_half_size, end_list_versions.first].min).to_a + middle_list_versions_with_sentinels = (middle_list_version_sentinels | middle_list_version_steps | middle_list_version_window).sort + middle_list_versions_with_gaps = middle_list_versions_with_sentinels.each_cons(2).flat_map do |previous_version, v| + v == previous_version + 1 ? [v] : [:gap, v] + end[...-1] + middle_list_versions = middle_list_versions_with_gaps lists << tag.ul(:id => "versions-navigation-list-start", :class => "pagination pagination-sm mt-1") do @@ -29,13 +37,14 @@ module NumberedPaginationHelper "pt-1 px-1 mx-n1", # space reserved for focus outlines "position-relative" # required for centering when clicking "Version #n" ]) do - concat element_versions_pagination_item("...", :edge => [true, false]) if middle_list_versions.first > start_list_versions.last + 1 - middle_list_versions.each do |v| - concat element_versions_pagination_item(v, **yield(v), :active => v == active_version, - :edge => [v == start_list_versions.last + 1, - v == end_list_versions.first - 1]) + middle_list_versions.each_with_index do |v, i| + edge = [i.zero?, i == middle_list_versions.length - 1] + if v == :gap + concat element_versions_pagination_item("...", :edge => edge) + else + concat element_versions_pagination_item(v, **yield(v), :active => v == active_version, :edge => edge) + end end - concat element_versions_pagination_item("...", :edge => [false, true]) if middle_list_versions.last < end_list_versions.first - 1 end lists << tag.ul(:id => "versions-navigation-list-end", :class => "pagination pagination-sm mt-1") do diff --git a/test/helpers/numbered_pagination_helper_test.rb b/test/helpers/numbered_pagination_helper_test.rb index c94c84b53..680ab0ae5 100644 --- a/test/helpers/numbered_pagination_helper_test.rb +++ b/test/helpers/numbered_pagination_helper_test.rb @@ -274,6 +274,100 @@ class NumberedPaginationHelperTest < ActionView::TestCase end end + def test_element_versions_pagination_step + pagination = element_versions_pagination(35, :step_size => 10, :window_half_size => 0) { |v| sample_item_data v } + pagination_dom = Rails::Dom::Testing.html_document_fragment.parse(pagination) + assert_dom pagination_dom, "ul", :count => 3 do |lists| + assert_dom lists[0], "> li", 1 do |items| + check_version_link items.shift, sample_item_data(1) + end + assert_dom lists[1], "> li", 7 do |items| + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(10) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(20) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(30) + check_version_ellipsis items.shift + end + assert_dom lists[2], "> li", 1 do |items| + check_version_link items.shift, sample_item_data(35) + end + end + end + + def test_element_versions_pagination_step_end_touch + pagination = element_versions_pagination(31, :step_size => 10, :window_half_size => 0) { |v| sample_item_data v } + pagination_dom = Rails::Dom::Testing.html_document_fragment.parse(pagination) + assert_dom pagination_dom, "ul", :count => 3 do |lists| + assert_dom lists[0], "> li", 1 do |items| + check_version_link items.shift, sample_item_data(1) + end + assert_dom lists[1], "> li", 6 do |items| + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(10) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(20) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(30) + end + assert_dom lists[2], "> li", 1 do |items| + check_version_link items.shift, sample_item_data(31) + end + end + end + + def test_element_versions_pagination_step_window + pagination = element_versions_pagination(35, :active_version => 15, :step_size => 10, :window_half_size => 1) { |v| sample_item_data v } + pagination_dom = Rails::Dom::Testing.html_document_fragment.parse(pagination) + assert_dom pagination_dom, "ul", :count => 3 do |lists| + assert_dom lists[0], "> li", 1 do |items| + check_version_link items.shift, sample_item_data(1) + end + assert_dom lists[1], "> li", 11 do |items| + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(10) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(14) + check_version_link items.shift, sample_item_data(15), :active => true + check_version_link items.shift, sample_item_data(16) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(20) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(30) + check_version_ellipsis items.shift + end + assert_dom lists[2], "> li", 1 do |items| + check_version_link items.shift, sample_item_data(35) + end + end + end + + def test_element_versions_pagination_step_window_touch + pagination = element_versions_pagination(35, :active_version => 12, :step_size => 10, :window_half_size => 1) { |v| sample_item_data v } + pagination_dom = Rails::Dom::Testing.html_document_fragment.parse(pagination) + assert_dom pagination_dom, "ul", :count => 3 do |lists| + assert_dom lists[0], "> li", 1 do |items| + check_version_link items.shift, sample_item_data(1) + end + assert_dom lists[1], "> li", 10 do |items| + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(10) + check_version_link items.shift, sample_item_data(11) + check_version_link items.shift, sample_item_data(12), :active => true + check_version_link items.shift, sample_item_data(13) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(20) + check_version_ellipsis items.shift + check_version_link items.shift, sample_item_data(30) + check_version_ellipsis items.shift + end + assert_dom lists[2], "> li", 1 do |items| + check_version_link items.shift, sample_item_data(35) + end + end + end + private def sample_item_data(version) -- 2.39.5