actionset 0.2.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5026afa544f9def59209497c089522877b6ab900
4
- data.tar.gz: 3bfbd8ff3930d022ac45e8680390ad9a42c4406c
3
+ metadata.gz: 27ec348f94bbc668c2b2b0488ae39f551aa4eb07
4
+ data.tar.gz: 926fda73f52119dd20c4e355ff0a501d25238f54
5
5
  SHA512:
6
- metadata.gz: f78f95e0cf017f4a22dd8339cfb2338d4ca8c01c97a3d68d7f7200895e74572073be94bc1756fc115cee336660738f8988354275e794d5280b6c70028ecddf0a
7
- data.tar.gz: e165d731e37993c0a92a3d407642d7823dbaaf5414ae137a5d11fbdf1bb64bdfdb7c859c6c1cfae11acfcc596dc852b5957d336137dfa8330fec22b06d3b9bfd
6
+ metadata.gz: bdcadbe61ad8a0b6209015df5e9c0302ee6923d2aa33782b9baa75873650c457ac8e092513d5f2dd9dbc33a07f8ab6bc60a3f79121532bd8e429c4aa8098dc0e
7
+ data.tar.gz: f503e4ae5a77fc6a435b09519e1f26d09400e64e4b1d5d0354b7b7b6394400cbf8ee9c7d2419970919dbc6e3cb3496f982c3c0eef1f6f29e7da3cec26997688a
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ v 0.3.0
2
+ - Add a `paginate_set` method that is a part of the `process_set` chain now
3
+ - Add `paginate` view helper for rendering a pagination navigation
1
4
  v 0.2.1
2
5
  - Extract the `set_filters_ivar` method so that app controllers can use it in a before action for filter forms that are present on multiple actions
3
6
  v 0.2.0
@@ -7,13 +7,13 @@ require 'ostruct'
7
7
 
8
8
  require 'action_set/version'
9
9
  require_relative './action_set/instructions/entry_value'
10
- require_relative './action_set/view_helpers'
10
+ require_relative './action_set/helpers/helper_methods'
11
11
 
12
12
  module ActionSet
13
13
  class Railtie < ::Rails::Railtie
14
14
  initializer 'action_set.view_helpers' do
15
15
  ActiveSupport.on_load :action_view do
16
- include ViewHelpers
16
+ include Helpers::HelperMethods
17
17
  end
18
18
  end
19
19
  end
@@ -30,25 +30,31 @@ module ActionSet
30
30
  module InstanceMethods
31
31
  def process_set(set)
32
32
  @set = set
33
- sort_set(filter_set(ActiveSet.new(set)))
33
+ paginate_set(sort_set(filter_set(ActiveSet.new(set))))
34
34
  end
35
35
 
36
36
  def filter_set(set)
37
37
  set_filters_ivar
38
- active_set = set.is_a?(ActiveSet) ? set : ActiveSet.new(set)
38
+ active_set = ensure_active_set(set)
39
39
  active_set = active_set.filter(filter_structure) if filter_params.any?
40
40
  active_set
41
41
  end
42
42
 
43
43
  def sort_set(set)
44
- active_set = set.is_a?(ActiveSet) ? set : ActiveSet.new(set)
44
+ active_set = ensure_active_set(set)
45
45
  active_set = active_set.sort(sort_params) if sort_params.any?
46
46
  active_set
47
47
  end
48
48
 
49
+ def paginate_set(set)
50
+ active_set = ensure_active_set(set)
51
+ active_set = active_set.paginate(paginate_structure) if paginate_params.any?
52
+ active_set
53
+ end
54
+
49
55
  def export_set(set)
50
56
  return send_file(set, export_set_options(request.format)) if set.is_a?(String) && File.file?(set)
51
- active_set = set.is_a?(ActiveSet) ? set : ActiveSet.new(set)
57
+ active_set = ensure_active_set(set)
52
58
  transformed_data = active_set.transform(transform_structure)
53
59
  send_data(transformed_data, export_set_options(request.format))
54
60
  end
@@ -60,10 +66,6 @@ module ActionSet
60
66
 
61
67
  private
62
68
 
63
- def filter_params
64
- params.fetch(:filter, {}).to_unsafe_hash
65
- end
66
-
67
69
  def filter_structure
68
70
  filter_params.flatten_keys.reject { |_, v| v.blank? }.each_with_object({}) do |(keypath, value), memo|
69
71
  instruction = ActiveSet::Instructions::Entry.new(keypath, value)
@@ -75,6 +77,10 @@ module ActionSet
75
77
  end
76
78
  end
77
79
 
80
+ def paginate_structure
81
+ paginate_params.transform_values(&:to_i)
82
+ end
83
+
78
84
  def transform_structure
79
85
  {}.tap do |struct|
80
86
  struct[:format] = transform_params[:format] || request.format.symbol
@@ -90,10 +96,18 @@ module ActionSet
90
96
  end
91
97
  end
92
98
 
99
+ def filter_params
100
+ params.fetch(:filter, {}).to_unsafe_hash
101
+ end
102
+
93
103
  def sort_params
94
104
  params.fetch(:sort, {}).to_unsafe_hash
95
105
  end
96
106
 
107
+ def paginate_params
108
+ params.fetch(:paginate, {}).to_unsafe_hash
109
+ end
110
+
97
111
  def transform_params
98
112
  params.fetch(:transform, {}).to_unsafe_hash
99
113
  end
@@ -105,6 +119,12 @@ module ActionSet
105
119
  opts[:disposition] = :inline if %w[development test].include?(Rails.env.to_s)
106
120
  end
107
121
  end
122
+
123
+ def ensure_active_set(set)
124
+ return set if set.is_a?(ActiveSet)
125
+
126
+ ActiveSet.new(set)
127
+ end
108
128
  end
109
129
 
110
130
  def self.included(receiver)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './sort_linker'
4
+ require_relative './paginator'
5
+
6
+ module ActionSet
7
+ module Helpers
8
+ module HelperMethods
9
+ def sort_link(column, title)
10
+ Helpers::SortLinker.new(self).render(column, title)
11
+ end
12
+
13
+ def paginate(set)
14
+ Helpers::Paginator.new(self).render(set)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,165 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionSet
4
+ module Helpers
5
+ class Paginator
6
+ def initialize(template)
7
+ @template = template
8
+ @info = {}
9
+ end
10
+
11
+ def render(set)
12
+ @info = info_for_set(set)
13
+
14
+ content_tag(:ul, class: 'pagination') do
15
+ safe_join([
16
+ link_to_first_page,
17
+ link_to_prev_page,
18
+ link_to_prev_gap,
19
+ safe_join(relevant_page_numbers.map do |num|
20
+ page = PageInterface.new(num, @info)
21
+ link = link_to(page, page_link_url(page), rel: page.rel)
22
+ content_tag(:li, link, class: ['page', (page.current? ? 'active' : nil)].compact)
23
+ end),
24
+ link_to_next_gap,
25
+ link_to_next_page,
26
+ link_to_last_page
27
+ ].compact)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def info_for_set(set)
34
+ {
35
+ current_page: set.instructions.dig(:paginate, :page),
36
+ page_size: set.instructions.dig(:paginate, :size),
37
+ total_pages: (set.total_count.to_f / set.instructions.dig(:paginate, :size)).ceil,
38
+ left_window_size: 2,
39
+ right_window_size: 2
40
+ }
41
+ end
42
+
43
+ def relevant_page_numbers
44
+ current_page = [@info[:current_page]]
45
+ left_window = [*(@info[:current_page] - @info[:left_window_size])..@info[:current_page]]
46
+ right_window = [*@info[:current_page]..(@info[:current_page] + @info[:right_window_size])]
47
+
48
+ (left_window | current_page | right_window).sort.reject { |x| (x < 1) || (x > @info[:total_pages]) }
49
+ end
50
+
51
+ def page_link_url(page_number)
52
+ request.query_parameters
53
+ .merge(controller: controller.controller_path,
54
+ action: controller.action_name,
55
+ paginate: {
56
+ page: page_number
57
+ })
58
+ end
59
+
60
+ def link_to_prev_gap
61
+ return unless @info[:current_page] > 1
62
+ return unless @info[:current_page] <= @info[:total_pages]
63
+ return unless (@info[:current_page] - 1) > (@info[:left_window_size] + 1)
64
+
65
+ link = link_to('…', '#', onclick: 'return false;')
66
+ content_tag(:li, link, class: 'page prev_gap disabled')
67
+ end
68
+
69
+ def link_to_next_gap
70
+ return unless @info[:current_page] >= 1
71
+ return unless @info[:current_page] <= @info[:total_pages]
72
+ return unless (@info[:total_pages] - @info[:current_page]) > (@info[:right_window_size] + 1)
73
+
74
+ link = link_to('…', '#', onclick: 'return false;')
75
+ content_tag(:li, link, class: 'page next_gap disabled')
76
+ end
77
+
78
+ def link_to_first_page
79
+ return unless @info[:current_page] > 1
80
+
81
+ link = link_to('« First', page_link_url(1))
82
+ content_tag(:li, link, class: 'page first')
83
+ end
84
+
85
+ def link_to_prev_page
86
+ return unless @info[:current_page] > 1
87
+ return unless @info[:current_page] <= @info[:total_pages]
88
+
89
+ link = link_to('‹ Prev', page_link_url(@info[:current_page] - 1), rel: 'prev')
90
+ content_tag(:li, link, class: 'page prev')
91
+ end
92
+
93
+ def link_to_last_page
94
+ return unless @info[:current_page] != @info[:total_pages]
95
+ return unless @info[:current_page] <= @info[:total_pages]
96
+
97
+ link = link_to('Last »', page_link_url(@info[:total_pages]))
98
+ content_tag(:li, link, class: 'page last')
99
+ end
100
+
101
+ def link_to_next_page
102
+ return unless @info[:current_page] != @info[:total_pages]
103
+ return unless @info[:current_page] <= @info[:total_pages]
104
+
105
+ link = link_to('Next ›', page_link_url(@info[:current_page] + 1), rel: 'next')
106
+ content_tag(:li, link, class: 'page next')
107
+ end
108
+
109
+ # delegates view helper methods to @template
110
+ def method_missing(name, *args, &block)
111
+ @template.respond_to?(name) ? @template.send(name, *args, &block) : super
112
+ end
113
+
114
+ # Wraps a "page number" and provides some utility methods
115
+ class PageInterface
116
+ def initialize(page, info)
117
+ @page = page
118
+ @info = info
119
+ end
120
+
121
+ def number
122
+ @page
123
+ end
124
+
125
+ def current?
126
+ @page == @info[:current_page]
127
+ end
128
+
129
+ def first?
130
+ @page == 1
131
+ end
132
+
133
+ def last?
134
+ @page == @info[:total_pages]
135
+ end
136
+
137
+ def prev?
138
+ @page == @info[:current_page] - 1
139
+ end
140
+
141
+ def next?
142
+ @page == @info[:current_page] + 1
143
+ end
144
+
145
+ def rel
146
+ return 'next' if next?
147
+ return 'prev' if prev?
148
+ nil
149
+ end
150
+
151
+ def out_of_range?
152
+ @page > @info[:total_pages]
153
+ end
154
+
155
+ def to_i
156
+ number
157
+ end
158
+
159
+ def to_s
160
+ number.to_s
161
+ end
162
+ end
163
+ end
164
+ end
165
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionSet
4
+ module Helpers
5
+ class SortLinker
6
+ def initialize(template)
7
+ @template = template
8
+ end
9
+
10
+ def render(column, title = nil)
11
+ column = column.to_s
12
+ title ||= sort_link_title(column)
13
+
14
+ @template.link_to title, sort_link_url(column)
15
+ end
16
+
17
+ private
18
+
19
+ def sort_link_title(column)
20
+ I18n.t(column,
21
+ scope: :attributes,
22
+ default: default_sort_link_title(column))
23
+ end
24
+
25
+ def sort_link_url(column)
26
+ @template.request
27
+ .query_parameters
28
+ .merge(controller: @template.controller.controller_path,
29
+ action: @template.controller.action_name,
30
+ sort: {
31
+ column => sort_link_direction(column)
32
+ })
33
+ end
34
+
35
+ def sort_link_direction(column)
36
+ return 'asc' unless sort_params_include_column?(column)
37
+ return 'asc' unless sort_params_only_include_valid_directions?
38
+
39
+ sort_direction_inverses = { 'asc' => 'desc', 'desc' => 'asc' }
40
+ sort_direction_inverses[@template.params.dig(:sort, column).to_s]
41
+ end
42
+
43
+ def default_sort_link_title(column)
44
+ ActiveSet::Instructions::Entry::KeyPath.new(column).titleized
45
+ end
46
+
47
+ def sort_params_include_column?(column)
48
+ @template.params[:sort]&.keys&.include?(column.to_s)
49
+ end
50
+
51
+ def sort_params_only_include_valid_directions?
52
+ (sort_params_directions - %w[asc desc]).empty?
53
+ end
54
+
55
+ def sort_params_directions
56
+ @template.params[:sort]&.values&.map(&:to_s)&.uniq
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActionSet
4
- VERSION = '0.2.1'
4
+ VERSION = '0.3.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actionset
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Stephen Margheim
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-10-25 00:00:00.000000000 Z
11
+ date: 2017-10-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activeset
@@ -227,9 +227,11 @@ files:
227
227
  - bin/setup
228
228
  - config.ru
229
229
  - lib/action_set.rb
230
+ - lib/action_set/helpers/helper_methods.rb
231
+ - lib/action_set/helpers/paginator.rb
232
+ - lib/action_set/helpers/sort_linker.rb
230
233
  - lib/action_set/instructions/entry_value.rb
231
234
  - lib/action_set/version.rb
232
- - lib/action_set/view_helpers.rb
233
235
  homepage: https://github.com/fractaledmind/actionset
234
236
  licenses:
235
237
  - MIT
@@ -1,39 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ActionSet
4
- module ViewHelpers
5
- def sort_link(column, title = nil)
6
- column = column.to_s
7
- title ||= sort_link_title(column)
8
-
9
- link_to title, sort_link_url(column)
10
- end
11
-
12
- private
13
-
14
- def sort_link_url(column)
15
- request.query_parameters.merge(controller: controller.controller_path,
16
- action: controller.action_name,
17
- sort: {
18
- column => sort_link_direction(column)
19
- })
20
- end
21
-
22
- def sort_link_title(column)
23
- I18n.t(column,
24
- scope: :attributes,
25
- default: default_sort_link_title(column))
26
- end
27
-
28
- def sort_link_direction(column)
29
- return 'asc' unless params[:sort]&.keys&.include?(column.to_s)
30
-
31
- sort_direction_inverses = { 'asc' => 'desc', 'desc' => 'asc' }
32
- sort_direction_inverses[params.dig(:sort, column)]
33
- end
34
-
35
- def default_sort_link_title(column)
36
- ActiveSet::Instructions::Entry::KeyPath.new(column).titleized
37
- end
38
- end
39
- end