filterrific 5.2.3 → 5.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Rakefile +7 -7
- data/app/assets/javascripts/filterrific/filterrific.js +172 -0
- data/lib/filterrific/action_controller_extension.rb +14 -17
- data/lib/filterrific/action_view_extension.rb +33 -34
- data/lib/filterrific/active_record_extension.rb +6 -10
- data/lib/filterrific/engine.rb +5 -9
- data/lib/filterrific/has_reset_filterrific_url_mixin.rb +1 -4
- data/lib/filterrific/param_set.rb +18 -26
- data/lib/filterrific/version.rb +1 -3
- data/lib/filterrific.rb +2 -4
- data/spec/filterrific/action_controller_extension_spec.rb +78 -80
- data/spec/filterrific/action_view_extension_spec.rb +9 -12
- data/spec/filterrific/active_record_extension_spec.rb +24 -38
- data/spec/filterrific/param_set_spec.rb +89 -109
- data/spec/filterrific_spec.rb +1 -1
- data/spec/spec_helper.rb +5 -5
- metadata +3 -3
- data/app/assets/javascripts/filterrific/filterrific-jquery.js +0 -118
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a63c202db5dce43d16d986ad31a50abc21752cb7bd66771fce52c2ddc7a2614d
|
4
|
+
data.tar.gz: '090e98ad1d561910bbefd0095be81e8b0c622e29cd8cba5b12471379b9023b65'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d74dc358e308d4d84f04c6637bcd7c682b2ff671d9e11b36d9c9384434b4670d963e945ba80314e6e6e497fc54f7873b37e674bd5794d7f1b298c3912ac2190
|
7
|
+
data.tar.gz: b8731da2f59b0d70838c412fdacc1cbf103c76c1eba8668df5253a4d35948e7b60dd9f9bfbb8a021c1c11efe5ab7b945dca3f6490c0b58b66847a3a09dde717c
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
7
7
|
|
8
8
|
Filterrific major versions match the Ruby on Rails major versions they work with.
|
9
9
|
|
10
|
+
## [5.2.4] - Jan 30, 2023
|
11
|
+
|
12
|
+
* Remove JS dependency on jquery
|
13
|
+
* Make code compliant with standard.rb rules
|
14
|
+
|
10
15
|
## [5.2.3] - Mar. 18, 2022
|
11
16
|
|
12
17
|
* Added support for Rails 7
|
data/Rakefile
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
begin
|
2
|
-
require
|
2
|
+
require "bundler/setup"
|
3
3
|
rescue LoadError
|
4
|
-
puts
|
4
|
+
puts "You must `gem install bundler` and `bundle install` to run rake tasks"
|
5
5
|
end
|
6
6
|
|
7
7
|
Bundler::GemHelper.install_tasks
|
8
8
|
|
9
|
-
require
|
9
|
+
require "rake/testtask"
|
10
10
|
Rake::TestTask.new do |test|
|
11
|
-
test.libs <<
|
12
|
-
test.pattern =
|
11
|
+
test.libs << "spec"
|
12
|
+
test.pattern = "spec/**/*_spec.rb"
|
13
13
|
test.verbose = true
|
14
14
|
end
|
15
15
|
|
16
|
-
require
|
17
|
-
task default:
|
16
|
+
require "wwtd/tasks"
|
17
|
+
task default: "wwtd:local"
|
@@ -0,0 +1,172 @@
|
|
1
|
+
/**
|
2
|
+
* Javascript behaviors for Filterrific.
|
3
|
+
* http://filterrific.clearcove.ca
|
4
|
+
*
|
5
|
+
* Released under the MIT license
|
6
|
+
*
|
7
|
+
*/
|
8
|
+
|
9
|
+
// Create global Filterrific namespace
|
10
|
+
if (typeof Filterrific === 'undefined') {
|
11
|
+
var Filterrific = {};
|
12
|
+
}
|
13
|
+
|
14
|
+
// Define function to submit Filterrific filter form
|
15
|
+
Filterrific.submitFilterForm = function() {
|
16
|
+
var form = Filterrific.findParents(this, '#filterrific_filter')[0];
|
17
|
+
|
18
|
+
// send before event
|
19
|
+
form.dispatchEvent(new Event('loadingFilterrificResults'));
|
20
|
+
|
21
|
+
// turn on spinner
|
22
|
+
document.querySelector('.filterrific_spinner').style.display = 'block';
|
23
|
+
|
24
|
+
// Abort previous XMLHttpRequest request
|
25
|
+
if (Filterrific.lastRequest && Filterrific.lastRequest.readyState != 4) {
|
26
|
+
Filterrific.lastRequest.abort();
|
27
|
+
}
|
28
|
+
|
29
|
+
// Submit XMLHttpRequest request
|
30
|
+
Filterrific.lastRequest = Filterrific.prepareRequest(form);
|
31
|
+
Filterrific.lastRequest.send();
|
32
|
+
};
|
33
|
+
|
34
|
+
Filterrific.prepareRequest = function(form) {
|
35
|
+
var url = form.getAttribute('action'),
|
36
|
+
formData = new FormData(form),
|
37
|
+
params = new URLSearchParams(formData),
|
38
|
+
xhr = new XMLHttpRequest();
|
39
|
+
|
40
|
+
if (url.indexOf('?') < 0) {
|
41
|
+
url += '?' + params;
|
42
|
+
} else {
|
43
|
+
url += '&' + params;
|
44
|
+
}
|
45
|
+
|
46
|
+
xhr.open("GET", url, true);
|
47
|
+
xhr.setRequestHeader('Accept', 'text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01');
|
48
|
+
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
49
|
+
xhr.onreadystatechange = function() {
|
50
|
+
if (xhr.readyState === XMLHttpRequest.DONE) {
|
51
|
+
return Filterrific.processResponse(form, xhr);
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
return xhr;
|
56
|
+
}
|
57
|
+
|
58
|
+
Filterrific.processResponse = function(form, xhr) {
|
59
|
+
var rawResponse = (_ref = xhr.response) != null ? _ref : xhr.responseText,
|
60
|
+
type = xhr.getResponseHeader('Content-Type'),
|
61
|
+
response;
|
62
|
+
|
63
|
+
if (typeof rawResponse === 'string' && typeof type === 'string') {
|
64
|
+
if (type.match(/\bjson\b/)) {
|
65
|
+
try {
|
66
|
+
response = JSON.parse(rawResponse);
|
67
|
+
} catch (_error) {}
|
68
|
+
} else if (type.match(/\b(?:java|ecma)script\b/)) {
|
69
|
+
script = document.createElement('script');
|
70
|
+
script.setAttribute('nonce', Filterrific.cspNonce());
|
71
|
+
script.text = rawResponse;
|
72
|
+
document.head.appendChild(script).parentNode.removeChild(script);
|
73
|
+
} else if (type.match(/\b(xml|html|svg)\b/)) {
|
74
|
+
parser = new DOMParser();
|
75
|
+
type = type.replace(/;.+/, '');
|
76
|
+
try {
|
77
|
+
response = parser.parseFromString(rawResponse, type);
|
78
|
+
} catch (_error) {}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
// send after event
|
83
|
+
form.dispatchEvent(new Event('loadedFilterrificResults'));
|
84
|
+
document.querySelector('.filterrific_spinner').style.display = 'none';
|
85
|
+
|
86
|
+
return response;
|
87
|
+
}
|
88
|
+
|
89
|
+
Filterrific.cspNonce = function() {
|
90
|
+
return document.querySelector("meta[name=csp-nonce]")?.content
|
91
|
+
}
|
92
|
+
|
93
|
+
Filterrific.findParents = function(elem, selector) {
|
94
|
+
var elements = [];
|
95
|
+
var ishaveselector = selector !== undefined;
|
96
|
+
|
97
|
+
while ((elem = elem.parentElement) !== null) {
|
98
|
+
if (elem.nodeType !== Node.ELEMENT_NODE) {
|
99
|
+
continue;
|
100
|
+
}
|
101
|
+
|
102
|
+
if (!ishaveselector || elem.matches(selector)) {
|
103
|
+
elements.push(elem);
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
return elements;
|
108
|
+
};
|
109
|
+
|
110
|
+
Filterrific.observe_field = function(inputs_selector, frequency, callback) {
|
111
|
+
frequency = frequency * 1000;
|
112
|
+
|
113
|
+
document.querySelectorAll(inputs_selector).forEach(input => {
|
114
|
+
var prev = input.value;
|
115
|
+
var check = function() {
|
116
|
+
// if removed clear the interval and don't fire the callback
|
117
|
+
if (removed()) {
|
118
|
+
if(ti) clearInterval(ti);
|
119
|
+
return;
|
120
|
+
}
|
121
|
+
var val = input.value;
|
122
|
+
if (prev != val) {
|
123
|
+
prev = val;
|
124
|
+
|
125
|
+
// invokes the callback on $this
|
126
|
+
if (callback && typeof callback === 'function') {
|
127
|
+
callback.call(input);
|
128
|
+
}
|
129
|
+
}
|
130
|
+
};
|
131
|
+
|
132
|
+
var removed = function() {
|
133
|
+
return input.closest('html').length == 0
|
134
|
+
};
|
135
|
+
|
136
|
+
var reset = function() {
|
137
|
+
if (ti) {
|
138
|
+
clearInterval(ti);
|
139
|
+
ti = setInterval(check, frequency);
|
140
|
+
}
|
141
|
+
};
|
142
|
+
check();
|
143
|
+
var ti = setInterval(check, frequency); // invoke check periodically
|
144
|
+
// reset counter after user interaction
|
145
|
+
// mousemove is for selects
|
146
|
+
input.addEventListener('keyup', reset);
|
147
|
+
input.addEventListener('click', reset);
|
148
|
+
input.addEventListener('mousemove', reset);
|
149
|
+
})
|
150
|
+
};
|
151
|
+
|
152
|
+
|
153
|
+
Filterrific.init = function() {
|
154
|
+
// Add change event handler to all Filterrific filter inputs.
|
155
|
+
var filterrificForm = document.querySelector('#filterrific_filter');
|
156
|
+
filterrificForm.querySelectorAll('input, textarea, select, textarea').forEach(input => {
|
157
|
+
input.addEventListener('change', Filterrific.submitFilterForm)
|
158
|
+
})
|
159
|
+
|
160
|
+
// Add periodic observer to selected inputs.
|
161
|
+
// Use this for text fields you want to observe for change, e.g., a search input.
|
162
|
+
Filterrific.observe_field(
|
163
|
+
".filterrific-periodically-observed",
|
164
|
+
0.5,
|
165
|
+
Filterrific.submitFilterForm
|
166
|
+
);
|
167
|
+
};
|
168
|
+
|
169
|
+
|
170
|
+
// Initialize event observers on document ready and turbolinks page:load
|
171
|
+
document.addEventListener('turbolinks:load', Filterrific.init);
|
172
|
+
document.addEventListener('DOMContentLoaded', Filterrific.init)
|
@@ -1,13 +1,11 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
1
|
#
|
3
2
|
# Adds Filterrific methods ActionController instances
|
4
3
|
#
|
5
4
|
module Filterrific
|
6
5
|
module ActionControllerExtension
|
7
|
-
|
8
6
|
include HasResetFilterrificUrlMixin
|
9
7
|
|
10
|
-
|
8
|
+
protected
|
11
9
|
|
12
10
|
# @param model_class [Class]
|
13
11
|
# @param filterrific_params [ActionController::Params, Hash] typically the
|
@@ -33,29 +31,29 @@ module Filterrific
|
|
33
31
|
def initialize_filterrific(model_class, filterrific_params, opts = {})
|
34
32
|
f_params = (filterrific_params || {}).stringify_keys
|
35
33
|
opts = opts.stringify_keys
|
36
|
-
pers_id = if
|
34
|
+
pers_id = if opts["persistence_id"] == false
|
37
35
|
nil
|
38
36
|
else
|
39
|
-
opts[
|
37
|
+
opts["persistence_id"] || compute_default_persistence_id
|
40
38
|
end
|
41
39
|
|
42
|
-
if
|
40
|
+
if f_params.delete("reset_filterrific")
|
43
41
|
# Reset query and session_persisted params
|
44
|
-
session[pers_id] = nil
|
45
|
-
redirect_to url_for({})
|
42
|
+
session[pers_id] = nil if pers_id
|
43
|
+
redirect_to url_for({}) and return false # requires `or return` in calling action.
|
46
44
|
end
|
47
45
|
|
48
46
|
f_params = compute_filterrific_params(model_class, f_params, opts, pers_id)
|
49
47
|
|
50
48
|
filterrific = Filterrific::ParamSet.new(model_class, f_params)
|
51
|
-
filterrific.select_options = opts[
|
52
|
-
session[pers_id] = filterrific.to_hash
|
49
|
+
filterrific.select_options = opts["select_options"]
|
50
|
+
session[pers_id] = filterrific.to_hash if pers_id
|
53
51
|
filterrific
|
54
52
|
end
|
55
53
|
|
56
54
|
# Computes a default persistence id based on controller and action name
|
57
55
|
def compute_default_persistence_id
|
58
|
-
[controller_name, action_name].join(
|
56
|
+
[controller_name, action_name].join("#")
|
59
57
|
end
|
60
58
|
|
61
59
|
# Computes filterrific params using a number of strategies. Limits params
|
@@ -68,17 +66,17 @@ module Filterrific
|
|
68
66
|
# Defaults to true.
|
69
67
|
# @param persistence_id [String, nil]
|
70
68
|
def compute_filterrific_params(model_class, filterrific_params, opts, persistence_id)
|
71
|
-
opts = {
|
69
|
+
opts = {"sanitize_params" => true}.merge(opts.stringify_keys)
|
72
70
|
r = (
|
73
71
|
filterrific_params.presence || # start with passed in params
|
74
72
|
(persistence_id && session[persistence_id].presence) || # then try session persisted params if persistence_id is present
|
75
|
-
opts[
|
73
|
+
opts["default_filter_params"] || # then use passed in opts
|
76
74
|
model_class.filterrific_default_filter_params # finally use model_class defaults
|
77
75
|
).stringify_keys
|
78
|
-
r.slice!(*opts[
|
76
|
+
r.slice!(*opts["available_filters"].map(&:to_s)) if opts["available_filters"]
|
79
77
|
# Sanitize params to prevent reflected XSS attack
|
80
78
|
if opts["sanitize_params"]
|
81
|
-
r.each { |k,v| r[k] = sanitize_filterrific_param(r[k]) }
|
79
|
+
r.each { |k, v| r[k] = sanitize_filterrific_param(r[k]) }
|
82
80
|
end
|
83
81
|
r
|
84
82
|
end
|
@@ -94,7 +92,7 @@ module Filterrific
|
|
94
92
|
val.map { |e| sanitize_filterrific_param(e) }
|
95
93
|
when Hash
|
96
94
|
# Return Hash
|
97
|
-
val.
|
95
|
+
val.each_with_object({}) { |(k, v), m| m[k] = sanitize_filterrific_param(v); }
|
98
96
|
when NilClass
|
99
97
|
# Nothing to do, use val as is
|
100
98
|
val
|
@@ -105,6 +103,5 @@ module Filterrific
|
|
105
103
|
val
|
106
104
|
end
|
107
105
|
end
|
108
|
-
|
109
106
|
end
|
110
107
|
end
|
@@ -1,10 +1,8 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
1
|
#
|
3
2
|
# Adds Filterrific view helpers to ActionView instances
|
4
3
|
#
|
5
4
|
module Filterrific
|
6
5
|
module ActionViewExtension
|
7
|
-
|
8
6
|
include HasResetFilterrificUrlMixin
|
9
7
|
|
10
8
|
# Sets all options on form_for to defaults that work with Filterrific
|
@@ -17,8 +15,8 @@ module Filterrific
|
|
17
15
|
options[:html][:method] ||= :get
|
18
16
|
options[:html][:id] ||= :filterrific_filter
|
19
17
|
options[:url] ||= url_for(
|
20
|
-
:
|
21
|
-
:
|
18
|
+
controller: controller.controller_name,
|
19
|
+
action: controller.action_name
|
22
20
|
)
|
23
21
|
form_for(record, options, &block)
|
24
22
|
end
|
@@ -27,7 +25,7 @@ module Filterrific
|
|
27
25
|
def render_filterrific_spinner
|
28
26
|
%(
|
29
27
|
<span class="filterrific_spinner" style="display:none;">
|
30
|
-
#{
|
28
|
+
#{image_tag("filterrific/filterrific-spinner.gif", alt: "", role: "presentation")}
|
31
29
|
</span>
|
32
30
|
).html_safe
|
33
31
|
end
|
@@ -65,23 +63,25 @@ module Filterrific
|
|
65
63
|
# Override the target URL attributes to be used for `url_for`. Default: {} (current URL).
|
66
64
|
def filterrific_sorting_link(filterrific, sort_key, opts = {})
|
67
65
|
opts = {
|
68
|
-
:
|
69
|
-
:
|
70
|
-
:
|
71
|
-
:
|
72
|
-
:
|
73
|
-
:
|
74
|
-
:
|
75
|
-
:
|
76
|
-
:
|
77
|
-
:
|
66
|
+
active_column_class: "filterrific_current_sort_column",
|
67
|
+
inactive_column_class: "filterrific_sort_column",
|
68
|
+
ascending_indicator: "⬆",
|
69
|
+
default_sort_direction: "asc",
|
70
|
+
descending_indicator: "⬇",
|
71
|
+
html_attrs: {},
|
72
|
+
label: sort_key.to_s.humanize,
|
73
|
+
sorting_scope_name: :sorted_by,
|
74
|
+
url_for_attrs: {},
|
75
|
+
as: :filterrific
|
78
76
|
}.merge(opts)
|
79
77
|
opts.merge!(
|
80
|
-
:
|
81
|
-
:
|
82
|
-
:
|
83
|
-
:
|
84
|
-
|
78
|
+
html_attrs: opts[:html_attrs].with_indifferent_access,
|
79
|
+
current_sorting: (current_sorting = filterrific.send(opts[:sorting_scope_name])),
|
80
|
+
current_sort_key: current_sorting ? current_sorting.gsub(/_asc|_desc/, "") : nil,
|
81
|
+
current_sort_direction: if current_sorting
|
82
|
+
current_sorting.end_with?("_desc") ? "desc" : "asc"
|
83
|
+
end,
|
84
|
+
current_sort_direction_indicator: (current_sorting.end_with?("_desc") ? opts[:descending_indicator] : opts[:ascending_indicator])
|
85
85
|
)
|
86
86
|
new_sort_key = sort_key.to_s
|
87
87
|
if new_sort_key == opts[:current_sort_key]
|
@@ -93,7 +93,7 @@ module Filterrific
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
-
|
96
|
+
protected
|
97
97
|
|
98
98
|
# Renders HTML to reverse sort order on currently sorted column.
|
99
99
|
# @param filterrific [Filterrific::ParamSet]
|
@@ -102,20 +102,20 @@ module Filterrific
|
|
102
102
|
# @return [String] an HTML fragment
|
103
103
|
def filterrific_sorting_link_reverse_order(filterrific, new_sort_key, opts)
|
104
104
|
# current sort column, toggle search_direction
|
105
|
-
new_sort_direction =
|
106
|
-
new_sorting = safe_join([new_sort_key, new_sort_direction],
|
105
|
+
new_sort_direction = opts[:current_sort_direction] == "asc" ? "desc" : "asc"
|
106
|
+
new_sorting = safe_join([new_sort_key, new_sort_direction], "_")
|
107
107
|
css_classes = safe_join([
|
108
108
|
opts[:active_column_class],
|
109
109
|
opts[:html_attrs].delete(:class)
|
110
|
-
].compact,
|
110
|
+
].compact, " ")
|
111
111
|
new_filterrific_params = filterrific.to_hash
|
112
|
-
|
113
|
-
|
112
|
+
.with_indifferent_access
|
113
|
+
.merge(opts[:sorting_scope_name] => new_sorting)
|
114
114
|
url_for_attrs = opts[:url_for_attrs].merge(opts[:as] => new_filterrific_params)
|
115
115
|
link_to(
|
116
|
-
safe_join([opts[:label], opts[:current_sort_direction_indicator]],
|
116
|
+
safe_join([opts[:label], opts[:current_sort_direction_indicator]], " "),
|
117
117
|
url_for(url_for_attrs),
|
118
|
-
opts[:html_attrs].reverse_merge(:
|
118
|
+
opts[:html_attrs].reverse_merge(class: css_classes, method: :get, remote: true)
|
119
119
|
)
|
120
120
|
end
|
121
121
|
|
@@ -126,21 +126,20 @@ module Filterrific
|
|
126
126
|
# @return [String] an HTML fragment
|
127
127
|
def filterrific_sorting_link_new_column(filterrific, new_sort_key, opts)
|
128
128
|
new_sort_direction = opts[:default_sort_direction]
|
129
|
-
new_sorting = safe_join([new_sort_key, new_sort_direction],
|
129
|
+
new_sorting = safe_join([new_sort_key, new_sort_direction], "_")
|
130
130
|
css_classes = safe_join([
|
131
131
|
opts[:inactive_column_class],
|
132
132
|
opts[:html_attrs].delete(:class)
|
133
|
-
].compact,
|
133
|
+
].compact, " ")
|
134
134
|
new_filterrific_params = filterrific.to_hash
|
135
|
-
|
136
|
-
|
135
|
+
.with_indifferent_access
|
136
|
+
.merge(opts[:sorting_scope_name] => new_sorting)
|
137
137
|
url_for_attrs = opts[:url_for_attrs].merge(opts[:as] => new_filterrific_params)
|
138
138
|
link_to(
|
139
139
|
opts[:label],
|
140
140
|
url_for(url_for_attrs),
|
141
|
-
opts[:html_attrs].reverse_merge(:
|
141
|
+
opts[:html_attrs].reverse_merge(class: css_classes, method: :get, remote: true)
|
142
142
|
)
|
143
143
|
end
|
144
|
-
|
145
144
|
end
|
146
145
|
end
|
@@ -1,12 +1,10 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
1
|
#
|
3
2
|
# Adds Filterrific methods to ActiveRecord::Base model_class.
|
4
3
|
#
|
5
|
-
require
|
4
|
+
require "filterrific/param_set"
|
6
5
|
|
7
6
|
module Filterrific
|
8
7
|
module ActiveRecordExtension
|
9
|
-
|
10
8
|
# Adds Filterrific behavior to class when called like so:
|
11
9
|
#
|
12
10
|
# filterrific(
|
@@ -34,7 +32,6 @@ module Filterrific
|
|
34
32
|
validate_filterrific_available_filters
|
35
33
|
assign_filterrific_default_filter_params(opts)
|
36
34
|
validate_filterrific_default_filter_params
|
37
|
-
|
38
35
|
end
|
39
36
|
|
40
37
|
# Returns ActiveRecord relation based on filterrific_param_set.
|
@@ -46,7 +43,7 @@ module Filterrific
|
|
46
43
|
unless filterrific_param_set.is_a?(Filterrific::ParamSet)
|
47
44
|
raise(
|
48
45
|
ArgumentError,
|
49
|
-
"Invalid Filterrific::ParamSet: #{
|
46
|
+
"Invalid Filterrific::ParamSet: #{filterrific_param_set.inspect}"
|
50
47
|
)
|
51
48
|
end
|
52
49
|
|
@@ -69,7 +66,7 @@ module Filterrific
|
|
69
66
|
ar_rel
|
70
67
|
end
|
71
68
|
|
72
|
-
|
69
|
+
protected
|
73
70
|
|
74
71
|
# Defines a :sorted_by scope based on attrs
|
75
72
|
# @param attrs [Hash] with keys as
|
@@ -83,7 +80,7 @@ module Filterrific
|
|
83
80
|
# @return [void]
|
84
81
|
def assign_filterrific_available_filters(opts)
|
85
82
|
self.filterrific_available_filters = (
|
86
|
-
filterrific_available_filters + (opts[
|
83
|
+
filterrific_available_filters + (opts["available_filters"] || [])
|
87
84
|
).map(&:to_s).uniq.sort
|
88
85
|
end
|
89
86
|
|
@@ -97,7 +94,7 @@ module Filterrific
|
|
97
94
|
|
98
95
|
def assign_filterrific_default_filter_params(opts)
|
99
96
|
self.filterrific_default_filter_params = (
|
100
|
-
opts[
|
97
|
+
opts["default_filter_params"] || {}
|
101
98
|
).stringify_keys
|
102
99
|
end
|
103
100
|
|
@@ -106,9 +103,8 @@ module Filterrific
|
|
106
103
|
if (
|
107
104
|
inv_fdfps = filterrific_default_filter_params.keys - filterrific_available_filters
|
108
105
|
).any?
|
109
|
-
raise(ArgumentError, "Invalid default filter params: #{
|
106
|
+
raise(ArgumentError, "Invalid default filter params: #{inv_fdfps.inspect}")
|
110
107
|
end
|
111
108
|
end
|
112
|
-
|
113
109
|
end
|
114
110
|
end
|
data/lib/filterrific/engine.rb
CHANGED
@@ -1,16 +1,13 @@
|
|
1
|
-
|
1
|
+
require "filterrific/param_set"
|
2
2
|
|
3
|
-
require
|
3
|
+
require "filterrific/has_reset_filterrific_url_mixin"
|
4
4
|
|
5
|
-
require
|
6
|
-
|
7
|
-
require
|
8
|
-
require 'filterrific/action_view_extension'
|
9
|
-
require 'filterrific/active_record_extension'
|
5
|
+
require "filterrific/action_controller_extension"
|
6
|
+
require "filterrific/action_view_extension"
|
7
|
+
require "filterrific/active_record_extension"
|
10
8
|
|
11
9
|
module Filterrific
|
12
10
|
class Engine < ::Rails::Engine
|
13
|
-
|
14
11
|
# It's an engine so that we can add javascript and image assets
|
15
12
|
# to the asset pipeline.
|
16
13
|
|
@@ -27,6 +24,5 @@ module Filterrific
|
|
27
24
|
ActiveSupport.on_load :active_record do
|
28
25
|
extend Filterrific::ActiveRecordExtension
|
29
26
|
end
|
30
|
-
|
31
27
|
end
|
32
28
|
end
|
@@ -1,16 +1,13 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
1
|
#
|
3
2
|
# Adds reset_filterrific_url to controllers and views
|
4
3
|
#
|
5
4
|
module Filterrific
|
6
5
|
module HasResetFilterrificUrlMixin
|
7
|
-
|
8
6
|
# Returns a url that can be used to reset the Filterrific params
|
9
7
|
def reset_filterrific_url(opts = {})
|
10
8
|
url_for(
|
11
|
-
{
|
9
|
+
{filterrific: {reset_filterrific: true}}.merge(opts)
|
12
10
|
)
|
13
11
|
end
|
14
|
-
|
15
12
|
end
|
16
13
|
end
|
@@ -1,13 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'active_support/all'
|
4
|
-
require 'digest/sha1'
|
1
|
+
require "active_support/all"
|
2
|
+
require "digest/sha1"
|
5
3
|
|
6
4
|
module Filterrific
|
7
|
-
|
8
5
|
# FilterParamSet is a container to store FilterParams
|
9
6
|
class ParamSet
|
10
|
-
|
11
7
|
attr_accessor :model_class
|
12
8
|
attr_accessor :select_options
|
13
9
|
|
@@ -27,16 +23,16 @@ module Filterrific
|
|
27
23
|
# You might wonder "what if I want to change only one thing from the defaults?"
|
28
24
|
# Persistence, baby. By the time you submit changes to one filter, all the others
|
29
25
|
# will be already initialized with the defaults.
|
30
|
-
filterrific_params = model_class.filterrific_default_filter_params
|
26
|
+
filterrific_params = model_class.filterrific_default_filter_params if filterrific_params.blank?
|
31
27
|
if defined?(ActionController::Parameters) && filterrific_params.is_a?(ActionController::Parameters)
|
32
28
|
permissible_filter_params = []
|
33
29
|
model_class.filterrific_available_filters.each do |p|
|
34
|
-
if filterrific_params[p].is_a?(ActionController::Parameters)
|
35
|
-
|
30
|
+
permissible_filter_params << if filterrific_params[p].is_a?(ActionController::Parameters)
|
31
|
+
{p => filterrific_params[p].keys}
|
36
32
|
elsif filterrific_params[p].is_a?(Array)
|
37
|
-
|
33
|
+
{p => []}
|
38
34
|
else
|
39
|
-
|
35
|
+
p
|
40
36
|
end
|
41
37
|
end
|
42
38
|
filterrific_params = filterrific_params.permit(permissible_filter_params).to_h.stringify_keys
|
@@ -60,14 +56,13 @@ module Filterrific
|
|
60
56
|
def to_hash
|
61
57
|
{}.tap { |h|
|
62
58
|
model_class.filterrific_available_filters.each do |filter_name|
|
63
|
-
param_value =
|
64
|
-
|
65
|
-
when param_value.blank?
|
59
|
+
param_value = send(filter_name)
|
60
|
+
if param_value.blank?
|
66
61
|
# do nothing
|
67
|
-
|
62
|
+
elsif param_value.is_a?(Proc)
|
68
63
|
# evaluate Proc so it can be serialized
|
69
64
|
h[filter_name] = param_value.call
|
70
|
-
|
65
|
+
elsif param_value.is_a?(OpenStruct)
|
71
66
|
# convert OpenStruct to hash
|
72
67
|
h[filter_name] = param_value.marshal_dump
|
73
68
|
else
|
@@ -83,25 +78,24 @@ module Filterrific
|
|
83
78
|
to_hash.to_json
|
84
79
|
end
|
85
80
|
|
86
|
-
|
81
|
+
protected
|
87
82
|
|
88
83
|
# Conditions params: Evaluates Procs and type casts integer values.
|
89
84
|
# @param fp [Hash] the filterrific params hash
|
90
85
|
# @return[Hash] the conditioned params hash
|
91
86
|
def condition_filterrific_params(fp)
|
92
87
|
fp.each do |key, val|
|
93
|
-
|
94
|
-
when val.is_a?(Proc)
|
88
|
+
if val.is_a?(Proc)
|
95
89
|
# evaluate Procs
|
96
90
|
fp[key] = val.call
|
97
|
-
|
91
|
+
elsif val.is_a?(Array)
|
98
92
|
# type cast integers in the array
|
99
|
-
fp[key] = fp[key].map { |e| e
|
100
|
-
|
93
|
+
fp[key] = fp[key].map { |e| e.to_s.match?(integer_detector_regex) ? e.to_i : e }
|
94
|
+
elsif val.is_a?(Hash)
|
101
95
|
# type cast Hash to OpenStruct so that nested params render correctly
|
102
96
|
# in the form
|
103
97
|
fp[key] = OpenStruct.new(fp[key])
|
104
|
-
|
98
|
+
elsif val.is_a?(String) && val.match?(integer_detector_regex)
|
105
99
|
# type cast integer
|
106
100
|
fp[key] = fp[key].to_i
|
107
101
|
end
|
@@ -121,10 +115,8 @@ module Filterrific
|
|
121
115
|
model_class.filterrific_available_filters.each do |filter_name|
|
122
116
|
self.class.send(:attr_accessor, filter_name)
|
123
117
|
v = fp[filter_name]
|
124
|
-
|
118
|
+
send("#{filter_name}=", v) if v.present?
|
125
119
|
end
|
126
120
|
end
|
127
|
-
|
128
121
|
end
|
129
|
-
|
130
122
|
end
|
data/lib/filterrific/version.rb
CHANGED