filterrific 5.2.2 → 5.2.4
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 +5 -5
- data/CHANGELOG.md +9 -0
- data/README.md +7 -7
- data/Rakefile +7 -7
- data/app/assets/javascripts/filterrific/filterrific.js +172 -0
- data/doc/meta.md +17 -3
- data/doc/scratchpad.md +0 -28
- 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 +4 -6
- 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 +4 -5
- data/app/assets/javascripts/filterrific/filterrific-jquery.js +0 -118
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
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,15 @@ 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
|
+
|
15
|
+
## [5.2.3] - Mar. 18, 2022
|
16
|
+
|
17
|
+
* Added support for Rails 7
|
18
|
+
|
10
19
|
## [5.2.2] - Jul. 11, 2021
|
11
20
|
|
12
21
|
* Fixed Ruby 2.7 deprecated warning when trying to regex match an Integer.
|
data/README.md
CHANGED
@@ -39,13 +39,13 @@ to find out more!
|
|
39
39
|
|
40
40
|
Every commit to Filterrific is automatically tested against the following scenarios:
|
41
41
|
|
42
|
-
|Filterrific version | Rails version
|
43
|
-
|
44
|
-
| 5.x | Rails 5.x, 6.x | MRI 2.0.0, 2.1.7, 2.2.3, 2.3.1 | mysql2, postgresql |[](https://travis-ci.org/jhund/filterrific_demo)|
|
45
|
-
| 4.x | Rails 4.x
|
46
|
-
| 3.x | Rails 3.2
|
47
|
-
| 2.x | Rails 3.2
|
48
|
-
| 1.x | < 3.2
|
42
|
+
|Filterrific version | Rails version | Ruby environments | Database adapters | Build status |
|
43
|
+
|--------------------|---------------------|--------------------------------|------------------------------------|--------------|
|
44
|
+
| 5.x | Rails 5.x, 6.x, 7.x | MRI 2.0.0, 2.1.7, 2.2.3, 2.3.1 | mysql2, postgresql |[](https://travis-ci.org/jhund/filterrific_demo)|
|
45
|
+
| 4.x | Rails 4.x | MRI 2.0.0, 2.1.7, 2.2.3, 2.3.1 | mysql, mysql2, postgresql, sqlite3 |[](https://travis-ci.org/jhund/filterrific_demo)|
|
46
|
+
| 3.x | Rails 3.2 | MRI 2.0.0, 2.1.7 | mysql, mysql2, postgresql, sqlite3 | Not tested|
|
47
|
+
| 2.x | Rails 3.2 | MRI 1.9.3 | mysql, mysql2, postgresql, sqlite3 | Not tested|
|
48
|
+
| 1.x | < 3.2 | MRI <= 1.9.3 | mysql, mysql2, postgresql, sqlite3 | Not tested|
|
49
49
|
|
50
50
|
### Guidelines for submitting issues
|
51
51
|
|
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)
|
data/doc/meta.md
CHANGED
@@ -5,7 +5,6 @@ I use the gem-release gem
|
|
5
5
|
For more info see: https://github.com/svenfuchs/gem-release#usage
|
6
6
|
|
7
7
|
|
8
|
-
|
9
8
|
## Steps for an update
|
10
9
|
|
11
10
|
1. Update code and commit it.
|
@@ -22,11 +21,26 @@ For more info see: https://github.com/svenfuchs/gem-release#usage
|
|
22
21
|
`gem tag`
|
23
22
|
|
24
23
|
|
25
|
-
|
26
24
|
## How to run specs
|
27
25
|
|
28
|
-
`bundle exec rake`
|
26
|
+
`bundle exec rake` in the filterrific repo
|
27
|
+
|
28
|
+
|
29
|
+
## How to support a new major Rails version
|
30
|
+
|
31
|
+
Follow these steps when starting support for a new Rails major version:
|
32
|
+
|
33
|
+
* In `filterrific`
|
34
|
+
* Archive the current major rails version into a new branch off of master, e.g., when starting to support Rails 6, create a new branch for `5.x` from current master. This will be the branch used for ongoing 5.x support, and all new development for Rails 6 will happen in the `master` branch.
|
35
|
+
* Make all changes required to support a new version of Rails.
|
36
|
+
* Release the first `filterrific` version for Rails 6: `6.0.0`.
|
29
37
|
|
38
|
+
* In `filterrific_demo`
|
39
|
+
* Following the same example for Rails 6:
|
40
|
+
* Make sure that the `5.x` branch is up-to-date with master, and with current filterrific.
|
41
|
+
* Create a new `6.x` branch. In that branch create a brand new rails app using a current version of Rails 6.
|
42
|
+
* Make sure that the app works with the relevant version of `filterrific`.
|
43
|
+
* Deploy demo app to heroku.
|
30
44
|
|
31
45
|
|
32
46
|
## Travis CI
|
data/doc/scratchpad.md
CHANGED
@@ -2,36 +2,8 @@
|
|
2
2
|
|
3
3
|
## 2021 Initiative
|
4
4
|
|
5
|
-
* Update for Rails 6
|
6
|
-
* Implement API only version (no frontend)
|
7
|
-
* Update scope docs to use AREL
|
8
|
-
* Implement/document various front end scenarios:
|
9
|
-
* React
|
10
|
-
* Stimulus
|
11
|
-
* jQuery
|
12
|
-
* sprockets/webpacker
|
13
|
-
* Thoughts: Support the rails defaults (webpacker or sprockets?) out of the box, batteries included. Document how to do everything else.
|
14
|
-
* Work through issues and pull requests
|
15
|
-
|
16
|
-
improve the filterrific frontend handling:
|
17
|
-
|
18
|
-
* Remove invocation of init, document for devs to do it manually
|
19
|
-
https://github.com/jhund/filterrific/issues/199
|
20
|
-
* Replace jquery with vanilla JS
|
21
|
-
* Provide filterrific API version
|
22
|
-
* Make compatible with Rails 6
|
23
|
-
* Remove jquery dependency, make it easier to use with webpacker, document how to do init
|
24
|
-
https://github.com/jhund/filterrific/issues/198
|
25
|
-
|
26
|
-
* Support the following js scenarios:
|
27
|
-
* Sprockets
|
28
|
-
* Webpacker
|
29
|
-
* API only (e.g., for React)
|
30
|
-
|
31
|
-
|
32
5
|
## TODO
|
33
6
|
|
34
|
-
* add check that no filter_name conflicts with existing methods on included ActiveRecord class (See https://github.com/jhund/filterrific/issues/17)
|
35
7
|
* Update SW architecture and documentation according to Osterhuis Philosophy of software architecture/design book (mark advanced controller options as such to keep interface to learn simple)
|
36
8
|
|
37
9
|
## Travis
|
@@ -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
|