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 +4 -4
- data/CHANGELOG +3 -0
- data/lib/action_set.rb +30 -10
- data/lib/action_set/helpers/helper_methods.rb +18 -0
- data/lib/action_set/helpers/paginator.rb +165 -0
- data/lib/action_set/helpers/sort_linker.rb +60 -0
- data/lib/action_set/version.rb +1 -1
- metadata +5 -3
- data/lib/action_set/view_helpers.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 27ec348f94bbc668c2b2b0488ae39f551aa4eb07
|
4
|
+
data.tar.gz: 926fda73f52119dd20c4e355ff0a501d25238f54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
data/lib/action_set.rb
CHANGED
@@ -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/
|
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
|
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 =
|
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 =
|
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 =
|
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
|
data/lib/action_set/version.rb
CHANGED
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.
|
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-
|
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
|