zadok 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 802adfb741625bb0a92b833800900763c43650fc69575976ccc5e291b31e27b7
4
- data.tar.gz: c55686ea9b6959c99da063821f32fe7fa0af582c081829f3a450c79859b698be
3
+ metadata.gz: f672da6d9e4bf75eca14ab1b8659bfe92f362c38dfe22ced3fdf9a31c5c204cd
4
+ data.tar.gz: bf67606b9b15e5dcdf00fa1dd23e00e8b261a239b2f8fa51370f005206de86c5
5
5
  SHA512:
6
- metadata.gz: 613351795412bee396b05ad9b53c93fe3635b812b00baa5a78c1b0c30f601fb98e17f87ca42e6a555cf17c59d04c70ca3512799cfa3282a6a747b1e885cbf857
7
- data.tar.gz: 02bbf8b19aedf75f2fda96bea3e3f648d290d514ac84c939ac738d223bd630557539163c4ef6b72a52557316cbfadff8f53c3e37b9a4cf8dabd2c334f9cfc3bd
6
+ metadata.gz: 8a02b809e8ff1094dc12fc06dc7a2d1eacd3578affb18bddea6da73036c2a3771f6bcfee64ab24ee2547173e0363eacf3345ac99e60fc4f2e9ae732343cdcb86
7
+ data.tar.gz: 6a1a91ce657643eb57f948bd0efaff1e11b8dcb54282df3f508f5181638fe24c720fb13aff49b0125367834b21cb0fda9a945e0a50c4f55d0722d63ea577af5e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- zadok (0.1.4)
4
+ zadok (0.1.5)
5
5
  bootstrap (~> 4.0.0.beta2.1)
6
6
  cancancan (~> 2.0)
7
7
  font-awesome-rails (~> 4.7)
@@ -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,4 @@
1
+ - if filter_collection.active_filters?
2
+ #filter-form
3
+ = search_form_for current_search, url: filters_path, method: :put do |form|
4
+ = render "zadok/filters/form_fields", form: form
@@ -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
+ | &nbsp;
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,2 @@
1
+ = f.select filter.param, options_for_select(filter.options, filter.describe(search_params)),
2
+ { include_blank: true }, { multiple: true, class: "form-control" }
@@ -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,5 @@
1
+ - filter.options.each do |value, label|
2
+ .radio
3
+ label
4
+ = f.radio_button filter.param, value
5
+ = label
@@ -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,3 @@
1
+ = f.select filter.param,
2
+ options_for_select(filter.options, filter.describe(search_params)),
3
+ { include_blank: true }, filter.html_options
@@ -0,0 +1,2 @@
1
+ .textfield
2
+ = f.text_field filter.param, class: "form-control"
@@ -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,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zadok
4
+ module Filters
5
+ module Ransack
6
+ class HiddenFilter < Base
7
+ def describe(current_params)
8
+ current_params[param]
9
+ end
10
+
11
+ def type
12
+ :hidden
13
+ end
14
+ end
15
+ end
16
+ end
17
+ 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,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zadok
4
+ module Filters
5
+ module Ransack
6
+ class OptionsFilter < Base
7
+ def current_params
8
+ options[current_params[param]]
9
+ end
10
+
11
+ def type
12
+ :options
13
+ end
14
+ end
15
+ end
16
+ end
17
+ 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,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Zadok
4
+ module Filters
5
+ module Ransack
6
+ class TextfieldFilter < Base
7
+ def describe(current_params)
8
+ current_params[param]
9
+ end
10
+
11
+ def type
12
+ :textfield
13
+ end
14
+ end
15
+ end
16
+ end
17
+ 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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Zadok
4
- VERSION = "0.1.5"
4
+ VERSION = "0.1.6"
5
5
  end
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.5
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