zadok 0.1.5 → 0.1.6
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/Gemfile.lock +1 -1
- data/app/controllers/zadok_controller.rb +40 -0
- data/app/views/zadok/filters/_autocomplete.html.slim +8 -0
- data/app/views/zadok/filters/_edit.html.slim +4 -0
- data/app/views/zadok/filters/_form_fields.html.slim +17 -0
- data/app/views/zadok/filters/_hidden.html.slim +1 -0
- data/app/views/zadok/filters/_multiselect.slim +2 -0
- data/app/views/zadok/filters/_numeric_range_field.html.slim +13 -0
- data/app/views/zadok/filters/_options.html.slim +5 -0
- data/app/views/zadok/filters/_range.html.slim +9 -0
- data/app/views/zadok/filters/_select.html.slim +3 -0
- data/app/views/zadok/filters/_textfield.html.slim +2 -0
- data/app/views/zadok/filters/_typeable_multiselect.html.slim +25 -0
- data/app/views/zadok/index.html.slim +1 -1
- data/lib/zadok/filter_collection.rb +44 -0
- data/lib/zadok/filters/ransack/autocomplete_filter.rb +49 -0
- data/lib/zadok/filters/ransack/base.rb +68 -0
- data/lib/zadok/filters/ransack/hidden_filter.rb +17 -0
- data/lib/zadok/filters/ransack/multiselect_filter.rb +24 -0
- data/lib/zadok/filters/ransack/numeric_range_filter.rb +73 -0
- data/lib/zadok/filters/ransack/options_filter.rb +17 -0
- data/lib/zadok/filters/ransack/range_filter.rb +31 -0
- data/lib/zadok/filters/ransack/select_filter.rb +21 -0
- data/lib/zadok/filters/ransack/textfield_filter.rb +17 -0
- data/lib/zadok/filters/ransack/typeable_multiselect_filter.rb +19 -0
- data/lib/zadok/version.rb +1 -1
- metadata +23 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f672da6d9e4bf75eca14ab1b8659bfe92f362c38dfe22ced3fdf9a31c5c204cd
|
4
|
+
data.tar.gz: bf67606b9b15e5dcdf00fa1dd23e00e8b261a239b2f8fa51370f005206de86c5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8a02b809e8ff1094dc12fc06dc7a2d1eacd3578affb18bddea6da73036c2a3771f6bcfee64ab24ee2547173e0363eacf3345ac99e60fc4f2e9ae732343cdcb86
|
7
|
+
data.tar.gz: 6a1a91ce657643eb57f948bd0efaff1e11b8dcb54282df3f508f5181638fe24c720fb13aff49b0125367834b21cb0fda9a945e0a50c4f55d0722d63ea577af5e
|
data/Gemfile.lock
CHANGED
@@ -59,6 +59,46 @@ class ZadokController < ApplicationController
|
|
59
59
|
|
60
60
|
protected
|
61
61
|
|
62
|
+
def filter_collection
|
63
|
+
Zadok::FilterCollection.new(search_params, filters_namespace)
|
64
|
+
end
|
65
|
+
|
66
|
+
def filters_namespace
|
67
|
+
"filters/#{search_model}".classify.pluralize.constantize
|
68
|
+
end
|
69
|
+
|
70
|
+
def filtered_resources
|
71
|
+
current_search.result
|
72
|
+
end
|
73
|
+
|
74
|
+
def search_params
|
75
|
+
permitted_params.fetch(:q) { {} }
|
76
|
+
end
|
77
|
+
|
78
|
+
def search_model
|
79
|
+
raise "search_model method not implemented"
|
80
|
+
end
|
81
|
+
|
82
|
+
def current_search
|
83
|
+
search_model.ransack(search_params)
|
84
|
+
end
|
85
|
+
|
86
|
+
def search_results
|
87
|
+
current_search.result
|
88
|
+
end
|
89
|
+
|
90
|
+
def page
|
91
|
+
permitted_params.fetch(:page) { nil }
|
92
|
+
end
|
93
|
+
|
94
|
+
def per_page
|
95
|
+
permitted_params.fetch(:per_page) { 30 }
|
96
|
+
end
|
97
|
+
|
98
|
+
def current_sort
|
99
|
+
search_params.fetch(:s) { nil }
|
100
|
+
end
|
101
|
+
|
62
102
|
def permitted_params
|
63
103
|
params.permit(:page, :per_page, q: %i[s search_model])
|
64
104
|
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
.autocomplete.ui-front
|
2
|
+
= f.hidden_field filter.param, value: filter.describe(search_params)
|
3
|
+
= text_field_tag(filter.field_id, filter.field_value(search_params), { role: "autocomplete",
|
4
|
+
class: "form-control",
|
5
|
+
id: filter.field_id,
|
6
|
+
data: { source: filter.source,
|
7
|
+
parent: "#filter-form",
|
8
|
+
target_id: filter.target_field_id }})
|
@@ -0,0 +1,17 @@
|
|
1
|
+
= form.hidden_field :s, value: current_sort
|
2
|
+
= form.hidden_field :search_model, value: search_model
|
3
|
+
|
4
|
+
.row
|
5
|
+
- filter_collection.filters.each do |filter|
|
6
|
+
.col-lg-3.col-md-3.col-sm-4.col-xs-12[class=filter.type]
|
7
|
+
= form.label filter.param, filter.i18n_name
|
8
|
+
= render "zadok/filters/#{filter.type}", f: form, filter: filter
|
9
|
+
|
10
|
+
.row
|
11
|
+
.col-lg-3.col-md-3.col-sm-4.col-xs-12
|
12
|
+
|
|
13
|
+
= form.submit t("application.buttons.apply"), class: "btn btn-block btn-default"
|
14
|
+
.col-lg-6.col-md-6.col-sm-4.visible-sm-block.visible-md-block.visible-lg-block.hidden
|
15
|
+
.results.col-lg-3.col-md-3.col-sm-4.col-xs-12.text-right
|
16
|
+
= "#{t("filter.amount")}: "
|
17
|
+
.total-results.label.label-default
|
@@ -0,0 +1 @@
|
|
1
|
+
= f.hidden_field filter.param, value: filter.describe(search_params)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
.textfield.numeric_range_field
|
2
|
+
= text_field_tag filter.name, filter.value(params),
|
3
|
+
placeholder: I18n.t("filter_labels.numeric_range.placeholder"),
|
4
|
+
pattern: ' *- *\d+|\d+( *- *(\d+)?)?',
|
5
|
+
"data-role" => "numeric_range",
|
6
|
+
"data-left" => filter.params[0],
|
7
|
+
"data-right" => filter.params[1],
|
8
|
+
"data-content" => filter.popover_content,
|
9
|
+
"data-trigger" => "focus",
|
10
|
+
"data-html" => "true",
|
11
|
+
class: "form-control"
|
12
|
+
= f.hidden_field filter.params[0]
|
13
|
+
= f.hidden_field filter.params[1]
|
@@ -0,0 +1,9 @@
|
|
1
|
+
.range
|
2
|
+
= f.text_field filter.param, value: filter.describe(search_params),
|
3
|
+
data: { provide: :slider,
|
4
|
+
"slider-step": 5,
|
5
|
+
"slider-value": filter.describe(search_params),
|
6
|
+
"slider-ticks": filter.ticks,
|
7
|
+
"slider-ticks_labels": filter.ticks_labels,
|
8
|
+
"slider-ticks_positions": filter.ticks_positions,
|
9
|
+
"slider-tooltip": "hide" }
|
@@ -0,0 +1,25 @@
|
|
1
|
+
.textfield.input-group
|
2
|
+
= f.hidden_field filter.param, id: "#{filter.param}_id",
|
3
|
+
name: "",
|
4
|
+
value: ""
|
5
|
+
= f.text_field filter.param, class: "autocomplete form-control",
|
6
|
+
id: "#{filter.param}_name",
|
7
|
+
name: "",
|
8
|
+
value: "",
|
9
|
+
autocomplete:"off",
|
10
|
+
data: { id: "#{filter.data_id}",
|
11
|
+
path: filter.data_path,
|
12
|
+
type: filter.data_type }
|
13
|
+
.input-group-addon.add-entry id="#{filter.param}_button"
|
14
|
+
.fa.fa-plus
|
15
|
+
|
16
|
+
ul.active-filters id="#{filter.param}_list"
|
17
|
+
- if params[filter.param]
|
18
|
+
- params[filter.param].each do |value|
|
19
|
+
li
|
20
|
+
= filter.options[value]
|
21
|
+
= f.hidden_field filter.param, id: "#{filter.param}_#{value}",
|
22
|
+
value: value,
|
23
|
+
name: "q[#{filter.param}][]"
|
24
|
+
a.remove-entry[href="#"]
|
25
|
+
.fa.fa-times.pull-right
|
@@ -6,7 +6,7 @@
|
|
6
6
|
- if can?(:create, resource_name.classify.constantize)
|
7
7
|
= link_to t("#{resource_name.pluralize}.new"), resource_url_for(:new), class: "btn btn-primary text-white float-right"
|
8
8
|
|
9
|
-
= render "filters/edit"
|
9
|
+
= render "zadok/filters/edit"
|
10
10
|
|
11
11
|
table.table.table-light.table-bordered.table-striped.table-hover.table-sm
|
12
12
|
thead
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/inflector"
|
4
|
+
|
5
|
+
Dir[Rails.root + "app/filters/**/*.rb"].each do |file|
|
6
|
+
require_dependency file
|
7
|
+
end
|
8
|
+
|
9
|
+
module Zadok
|
10
|
+
class FilterCollection
|
11
|
+
attr_reader :filters, :params
|
12
|
+
|
13
|
+
def initialize(params, filters_namespace = Zadok::Filters)
|
14
|
+
@params = params
|
15
|
+
@filters = []
|
16
|
+
filters_namespace.constants.each do |constant|
|
17
|
+
unless constant.match?(/Ransack/)
|
18
|
+
@filters << "#{filters_namespace}::#{constant}".constantize.new
|
19
|
+
end
|
20
|
+
end
|
21
|
+
@filters.sort! { |a, b| a.index <=> b.index }
|
22
|
+
end
|
23
|
+
|
24
|
+
def current_filters
|
25
|
+
@filters.select do |filter|
|
26
|
+
filter.active_in? params
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def current_filter_params(params)
|
31
|
+
current_filters.flat_map(&:params).uniq.map do |param|
|
32
|
+
[param, params[param]]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def active_filters?
|
37
|
+
current_filters.count.positive?
|
38
|
+
end
|
39
|
+
|
40
|
+
def variable_results?
|
41
|
+
current_filters.any?(&:variable_results?)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zadok
|
4
|
+
module Filters
|
5
|
+
module Ransack
|
6
|
+
class AutocompleteFilter < Base
|
7
|
+
def describe(current_params)
|
8
|
+
current_params[param]
|
9
|
+
end
|
10
|
+
|
11
|
+
def model
|
12
|
+
raise NotImplementedError
|
13
|
+
end
|
14
|
+
|
15
|
+
def attr
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
def autocomplete_attribute
|
20
|
+
raise NotImplementedError
|
21
|
+
end
|
22
|
+
|
23
|
+
def source
|
24
|
+
model.to_s.downcase.pluralize
|
25
|
+
end
|
26
|
+
|
27
|
+
def options
|
28
|
+
Hash[model.uniq.pluck(attr, autocomplete_attribute)]
|
29
|
+
end
|
30
|
+
|
31
|
+
def type
|
32
|
+
:autocomplete
|
33
|
+
end
|
34
|
+
|
35
|
+
def field_id
|
36
|
+
"#{source.singularize}_#{autocomplete_attribute}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def target_field_id
|
40
|
+
"q_#{param}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def field_value(params)
|
44
|
+
model.find_by(attr => describe(params))&.send(autocomplete_attribute)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zadok
|
4
|
+
module Filters
|
5
|
+
module Ransack
|
6
|
+
class Base
|
7
|
+
def initialize(opts = {})
|
8
|
+
@params = opts[:params]
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :params
|
12
|
+
|
13
|
+
# most filters just use a single param
|
14
|
+
def param
|
15
|
+
params[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
def active_in?(current_params)
|
19
|
+
params.any? { |param| current_params.include? param }
|
20
|
+
end
|
21
|
+
|
22
|
+
def index
|
23
|
+
99
|
24
|
+
end
|
25
|
+
|
26
|
+
def i18n_name
|
27
|
+
I18n.t("filter.#{self.class.name.split('::').last.underscore}")
|
28
|
+
end
|
29
|
+
|
30
|
+
def title
|
31
|
+
i18n_name
|
32
|
+
end
|
33
|
+
|
34
|
+
def describe(_current_params)
|
35
|
+
raise NotImplementedError
|
36
|
+
end
|
37
|
+
|
38
|
+
# form control type
|
39
|
+
def type
|
40
|
+
raise NotImplementedError
|
41
|
+
end
|
42
|
+
|
43
|
+
def text(_current_params)
|
44
|
+
param
|
45
|
+
end
|
46
|
+
|
47
|
+
# options hash for filters with options
|
48
|
+
def options
|
49
|
+
I18n.t("filter_labels.#{param}").with_indifferent_access
|
50
|
+
end
|
51
|
+
|
52
|
+
# Each filter may opt to change the column(s) of the filtered admission
|
53
|
+
# list table - add or remove some.
|
54
|
+
def modify_columns(columns)
|
55
|
+
columns
|
56
|
+
end
|
57
|
+
|
58
|
+
def remove_from_params(current_params)
|
59
|
+
current_params.except(*params)
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_to_params(current_params, value)
|
63
|
+
current_params.merge(param => value)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zadok
|
4
|
+
module Filters
|
5
|
+
module Ransack
|
6
|
+
class MultiselectFilter < Base
|
7
|
+
def describe(current_params)
|
8
|
+
return [] if current_params[param].blank?
|
9
|
+
options.map do |key, value|
|
10
|
+
value if current_params[param].include?(key)
|
11
|
+
end.compact.join(", ")
|
12
|
+
end
|
13
|
+
|
14
|
+
def type
|
15
|
+
:multiselect
|
16
|
+
end
|
17
|
+
|
18
|
+
def active_in?(current_params)
|
19
|
+
super && (current_params[param] & options.keys).present?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "abbrev"
|
4
|
+
|
5
|
+
module Zadok
|
6
|
+
module Filters
|
7
|
+
module Ransack
|
8
|
+
class NumericRangeFilter < Base
|
9
|
+
def describe(current_params = {})
|
10
|
+
left, right = range_ends current_params
|
11
|
+
key = key_from_range_ends left, right
|
12
|
+
if key
|
13
|
+
I18n.t("filter_labels.numeric_range.#{key}", left: left, right: right)
|
14
|
+
else
|
15
|
+
left
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def range_ends(current_params = {})
|
20
|
+
params.map do |param|
|
21
|
+
x = current_params[param]
|
22
|
+
x == "" ? nil : x
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def key_from_range_ends(left, right)
|
27
|
+
if left && right
|
28
|
+
"closed" if left != right
|
29
|
+
elsif right
|
30
|
+
"left_open"
|
31
|
+
elsif left
|
32
|
+
"right_open"
|
33
|
+
else
|
34
|
+
raise "Both range ends missing; filter shouldn't be active"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def type
|
39
|
+
:numeric_range_field
|
40
|
+
end
|
41
|
+
|
42
|
+
def active_in?(current_params = {})
|
43
|
+
range_ends(current_params).any?
|
44
|
+
end
|
45
|
+
|
46
|
+
def name
|
47
|
+
prefix = common_prefix params.map(&:to_s)
|
48
|
+
prefix = params.join("_") + "_" if prefix.empty?
|
49
|
+
prefix + "range"
|
50
|
+
end
|
51
|
+
|
52
|
+
def common_prefix(strings)
|
53
|
+
strings.abbrev.keys.sort_by(&:length).first[0..-2]
|
54
|
+
end
|
55
|
+
|
56
|
+
def value(current_params)
|
57
|
+
left, right = range_ends current_params
|
58
|
+
if left == right
|
59
|
+
left
|
60
|
+
elsif left || right
|
61
|
+
"#{left} - #{right}"
|
62
|
+
else
|
63
|
+
""
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def popover_content
|
68
|
+
I18n.t("filter_labels.numeric_range.popover_text")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zadok
|
4
|
+
module Filters
|
5
|
+
module Ransack
|
6
|
+
class RangeFilter < Base
|
7
|
+
def describe(current_params)
|
8
|
+
current_params[param]
|
9
|
+
end
|
10
|
+
|
11
|
+
def type
|
12
|
+
:range
|
13
|
+
end
|
14
|
+
|
15
|
+
def ticks
|
16
|
+
options.map { |k, _v| k.to_s.to_i }
|
17
|
+
end
|
18
|
+
|
19
|
+
def ticks_labels
|
20
|
+
options.map { |_k, v| v }
|
21
|
+
end
|
22
|
+
|
23
|
+
def ticks_positions
|
24
|
+
ticks.map.with_index do |_tick, index|
|
25
|
+
(100 / (ticks.count.to_f - 1)) * index
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zadok
|
4
|
+
module Filters
|
5
|
+
module Ransack
|
6
|
+
class SelectFilter < Base
|
7
|
+
def describe(current_params)
|
8
|
+
current_params[param]
|
9
|
+
end
|
10
|
+
|
11
|
+
def type
|
12
|
+
:select
|
13
|
+
end
|
14
|
+
|
15
|
+
def html_options
|
16
|
+
{ class: "form-control" }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zadok
|
4
|
+
module Filters
|
5
|
+
module Ransack
|
6
|
+
class TypeableMultiselect < Base
|
7
|
+
def describe(current_params)
|
8
|
+
options.map do |key, value|
|
9
|
+
value if current_params[param].include?(key)
|
10
|
+
end.compact.join("|")
|
11
|
+
end
|
12
|
+
|
13
|
+
def type
|
14
|
+
:typeable_multiselect
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/zadok/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zadok
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leon Hooijer
|
@@ -197,6 +197,17 @@ files:
|
|
197
197
|
- app/controllers/zadok_controller.rb
|
198
198
|
- app/helpers/zadok_helper.rb
|
199
199
|
- app/views/zadok/edit.html.slim
|
200
|
+
- app/views/zadok/filters/_autocomplete.html.slim
|
201
|
+
- app/views/zadok/filters/_edit.html.slim
|
202
|
+
- app/views/zadok/filters/_form_fields.html.slim
|
203
|
+
- app/views/zadok/filters/_hidden.html.slim
|
204
|
+
- app/views/zadok/filters/_multiselect.slim
|
205
|
+
- app/views/zadok/filters/_numeric_range_field.html.slim
|
206
|
+
- app/views/zadok/filters/_options.html.slim
|
207
|
+
- app/views/zadok/filters/_range.html.slim
|
208
|
+
- app/views/zadok/filters/_select.html.slim
|
209
|
+
- app/views/zadok/filters/_textfield.html.slim
|
210
|
+
- app/views/zadok/filters/_typeable_multiselect.html.slim
|
200
211
|
- app/views/zadok/form/fields/_email_field.html.slim
|
201
212
|
- app/views/zadok/form/fields/_select.html.slim
|
202
213
|
- app/views/zadok/form/fields/_text_field.html.slim
|
@@ -204,6 +215,17 @@ files:
|
|
204
215
|
- app/views/zadok/new.html.slim
|
205
216
|
- lib/zadok.rb
|
206
217
|
- lib/zadok/engine.rb
|
218
|
+
- lib/zadok/filter_collection.rb
|
219
|
+
- lib/zadok/filters/ransack/autocomplete_filter.rb
|
220
|
+
- lib/zadok/filters/ransack/base.rb
|
221
|
+
- lib/zadok/filters/ransack/hidden_filter.rb
|
222
|
+
- lib/zadok/filters/ransack/multiselect_filter.rb
|
223
|
+
- lib/zadok/filters/ransack/numeric_range_filter.rb
|
224
|
+
- lib/zadok/filters/ransack/options_filter.rb
|
225
|
+
- lib/zadok/filters/ransack/range_filter.rb
|
226
|
+
- lib/zadok/filters/ransack/select_filter.rb
|
227
|
+
- lib/zadok/filters/ransack/textfield_filter.rb
|
228
|
+
- lib/zadok/filters/ransack/typeable_multiselect_filter.rb
|
207
229
|
- lib/zadok/link_renderer.rb
|
208
230
|
- lib/zadok/version.rb
|
209
231
|
- zadok.gemspec
|