jquery-tablesorter-rails-utils 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +4 -0
- data/LICENSE +21 -0
- data/README.md +133 -0
- data/Rakefile +2 -0
- data/jquery-tablesorter-rails-utils.gemspec +32 -0
- data/lib/jquery-tablesorter-rails-utils.rb +2 -0
- data/lib/jquery-tablesorter/rails-utils/ajax.rb +26 -0
- data/lib/jquery-tablesorter/rails-utils/ajax/action_controller.rb +52 -0
- data/lib/jquery-tablesorter/rails-utils/ajax/filter.rb +61 -0
- data/lib/jquery-tablesorter/rails-utils/ajax/handler.rb +248 -0
- data/lib/jquery-tablesorter/rails-utils/version.rb +9 -0
- metadata +159 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 78cbade05c4684cc14f69a730fef1e7dd40ec1b1
|
4
|
+
data.tar.gz: dc91520ae73b330131ff2e2c8adf1f659f7e6b77
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: d813e7bcdae763cd440088a3d71d37164d9758f5f8f23d11c8dff9328f1811c6dbce53f28771bb592c43bc31748199b84a77e93658460ec2c29c1d51fc8af39c
|
7
|
+
data.tar.gz: f5eaae71f1dc5fe2e92ec1e2273108ba187dd0c481e8ad84bd5122998e26d17bd9d022358614546afb9b8b1a0fc4b95706d6a7acd8951e86a773a9ddfed5e467
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2016 Erik-B. Ernst
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
# Jquery::Tablesorter::Rails::Utils
|
2
|
+
|
3
|
+
Helpful (hopefully! ;-) ) additions for jQuery tablesorter (only support for [Mottie's fork] targeted) when working with rails.
|
4
|
+
|
5
|
+
While still in early development - which might bring breaking changes with new releases - it is meant to provide helpful utilities for jquery-tablesorter in rails. At the current state of development it only supports a mechanism to help to work with Ajax based tables.
|
6
|
+
You have a helpful idea/code snippet for something which makes it easier to work with tablesorter and rails? Cool, feel free to create a pull request!
|
7
|
+
|
8
|
+
For further information how to work with jQuery tablesorter I recommend the excellent [documentation] in [Mottie's fork].
|
9
|
+
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Please note: Tablesorter has to be installed separately from this gem. You may use my packaged version ([jquery-tablesorter-gem]) or any other way to add it to your project.
|
14
|
+
|
15
|
+
Add this line to your application's Gemfile:
|
16
|
+
|
17
|
+
~~~ruby
|
18
|
+
gem 'jquery-tablesorter-rails-utils'
|
19
|
+
~~~
|
20
|
+
|
21
|
+
And then execute:
|
22
|
+
|
23
|
+
$ bundle
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
$ gem install jquery-tablesorter-rails-utils
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
### Module: Ajax
|
32
|
+
|
33
|
+
The following sections shows an example how to use the Ajax module. It currently only supports PostgreSQL.
|
34
|
+
|
35
|
+
So, to query rendered HTML rows of your Foo model you may do:
|
36
|
+
|
37
|
+
In your controller (don't forget to add your routes!):
|
38
|
+
|
39
|
+
~~~ruby
|
40
|
+
|
41
|
+
class FooController < ApplicationController
|
42
|
+
include JqueryTablesorter::RailsUtils::Ajax::ActionController
|
43
|
+
|
44
|
+
# Ajax query for the foo list rows
|
45
|
+
def query_list
|
46
|
+
base_query = Foo.my_scope
|
47
|
+
|
48
|
+
foo_columns()
|
49
|
+
resp = create_query_response(base_query, partial: 'my_partial_foo_row')
|
50
|
+
|
51
|
+
render json: resp
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def foo_columns
|
57
|
+
ts_ajax_handler.create_filter_info(:name, Foo)
|
58
|
+
ts_ajax_handler.create_filter_info(:other_attribute_name_of_foo, Foo)
|
59
|
+
# Let's say, there is a global filter, too. The position is the param
|
60
|
+
# tablesorter submits on an request.
|
61
|
+
ts_ajax_handler.create_filter_info(:all, Foo, { global_filter: true, position: 5 })
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
~~~
|
66
|
+
|
67
|
+
In the .coffee file you prepare your tablesorter instance and may add code like this:
|
68
|
+
|
69
|
+
~~~coffee
|
70
|
+
|
71
|
+
$('#my_ajax_table').tablesorter(
|
72
|
+
# ...
|
73
|
+
).tablesorterPager(
|
74
|
+
# your pager settings..
|
75
|
+
# if data tag is given, handle this table as ajax table
|
76
|
+
if query_url = current_table.data('query-url')
|
77
|
+
ajax_pager =
|
78
|
+
processAjaxOnInit: true
|
79
|
+
ajaxUrl: query_url
|
80
|
+
ajaxError: null
|
81
|
+
ajaxObject:
|
82
|
+
dataType: 'json'
|
83
|
+
ajaxProcessing: (result, table, xhr) ->
|
84
|
+
if result
|
85
|
+
result.total = result['total_rows']
|
86
|
+
result.filteredRows = result['filtered_rows']
|
87
|
+
if result.hasOwnProperty('data')
|
88
|
+
result.rows = $(result.data) # rendered <tr>s
|
89
|
+
return result
|
90
|
+
)
|
91
|
+
~~~
|
92
|
+
|
93
|
+
In your view, the table partials could look like:
|
94
|
+
|
95
|
+
~~~haml
|
96
|
+
|
97
|
+
%table#my_ajax_table{ 'data-query-url': 'foo/query?&page={page}&size={size}&{sortList:sort}&{filterList:filter}' }
|
98
|
+
%thead
|
99
|
+
%tr
|
100
|
+
%th= name
|
101
|
+
%th= other_attribute_name_of_foo
|
102
|
+
%tfoot
|
103
|
+
= render partial: 'your_footer_partial'
|
104
|
+
%tbody
|
105
|
+
~~~
|
106
|
+
|
107
|
+
And the partial for the table rows:
|
108
|
+
|
109
|
+
~~~haml
|
110
|
+
|
111
|
+
= records.each do |foo|
|
112
|
+
%tr
|
113
|
+
%td= foo.name
|
114
|
+
%td= foo.other_attribute_name_of_foo
|
115
|
+
~~~
|
116
|
+
|
117
|
+
|
118
|
+
## Licensing
|
119
|
+
|
120
|
+
* Licensed under the [MIT](http://www.opensource.org/licenses/mit-license.php) license.
|
121
|
+
|
122
|
+
## Contributing
|
123
|
+
|
124
|
+
1. Fork it
|
125
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
126
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
127
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
128
|
+
5. Create new Pull Request
|
129
|
+
|
130
|
+
|
131
|
+
[Mottie's fork]: https://github.com/Mottie/tablesorter
|
132
|
+
[documentation]: http://mottie.github.com/tablesorter/docs/index.html
|
133
|
+
[jquery-tablesorter-gem]: https://github.com/themilkman/jquery-tablesorter-rails
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'jquery-tablesorter/rails-utils/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'jquery-tablesorter-rails-utils'
|
8
|
+
spec.version = JqueryTablesorter::RailsUtils::VERSION
|
9
|
+
spec.authors = ['Erik-B. Ernst', 'Thomas Halter']
|
10
|
+
spec.email = ['github@black-milk.de']
|
11
|
+
|
12
|
+
spec.summary = %q{Some helpers to work with jQuery tablesorter and Ruby on Rails}
|
13
|
+
spec.description = %q{Some helpers to work with jQuery tablesorter and Ruby on Rails.}
|
14
|
+
spec.homepage = 'https://github.com/themilkman/jquery-tablesorter-rails-utils'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.required_ruby_version = '>= 1.9.3'
|
18
|
+
|
19
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
20
|
+
f.match(%r{^(test|spec|features)/})
|
21
|
+
end
|
22
|
+
|
23
|
+
spec.require_paths = ['lib']
|
24
|
+
|
25
|
+
spec.add_dependency 'activerecord', '>= 4.0', '< 6.0'
|
26
|
+
spec.add_dependency 'activesupport', '>= 4.0', '< 6.0'
|
27
|
+
spec.add_dependency 'actionview', '>= 4.0', '< 6.0'
|
28
|
+
spec.add_dependency 'pg'
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.13'
|
31
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Adds mechanisms to work with Ajax based tables and tablesorter.
|
2
|
+
# Current limitions (extract ;-P):
|
3
|
+
# * It does not support sorting by multiple columns.
|
4
|
+
# * Currently only PostgreSQL is supported
|
5
|
+
#
|
6
|
+
# Usage:
|
7
|
+
# Includet this module in your controller and call methods in your query-action,
|
8
|
+
# where the results can be used to build the response.
|
9
|
+
#
|
10
|
+
# Further ToDos/plans/ideas/dreams:
|
11
|
+
# * There might be a possibility to pass a block for each column-operation such
|
12
|
+
# as filtering or sorting and allow more dynamic work. This might happen before or better
|
13
|
+
# instead the standard processing. (partly done with the filter_mapping filter-parameter)
|
14
|
+
# * Maybe it'd be possible to allow multi-column sorting somehow.
|
15
|
+
# * In some cases it could make sense not to cast all columns to strings/varchars. So, an optionally passed
|
16
|
+
# type for a column might get evaluated/used in a different manner. (done for DateTime)
|
17
|
+
|
18
|
+
module JqueryTablesorter
|
19
|
+
module RailsUtils
|
20
|
+
module Ajax
|
21
|
+
require 'jquery-tablesorter/rails-utils/ajax/filter'
|
22
|
+
require 'jquery-tablesorter/rails-utils/ajax/handler'
|
23
|
+
require 'jquery-tablesorter/rails-utils/ajax/action_controller'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Controller concern to help with ajax jquery tablesorter requests.
|
2
|
+
# It handles sorting and filtering.
|
3
|
+
|
4
|
+
module JqueryTablesorter
|
5
|
+
module RailsUtils
|
6
|
+
module Ajax
|
7
|
+
module ActionController
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
|
11
|
+
# A generalized method to handle tablesorter queries. It's meant to be used in the corresponding
|
12
|
+
# Controller action. Params:
|
13
|
+
# clazz: The model's primary class
|
14
|
+
# base_query: If there are any relevant joins or so -> pass the AR relation here
|
15
|
+
# partial (optional): path to the partial to be rendered
|
16
|
+
def create_query_html_response(base_query, partial: 'row')
|
17
|
+
resp_data = ts_ajax_handler.query_data(base_query)
|
18
|
+
|
19
|
+
records = resp_data.delete(:records)
|
20
|
+
resp_data[:data] = render_response_html(records, partial: partial)
|
21
|
+
|
22
|
+
return resp_data
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Render the html rows for the given records and an optional named partial.
|
28
|
+
# Returns HTML string or nil
|
29
|
+
def render_response_html(records, partial: 'row' )
|
30
|
+
output = render_to_string partial: partial, locals: { records: records }
|
31
|
+
|
32
|
+
unless records.any? # if the query had 0 results, it will return a string which has let jquery crash
|
33
|
+
output = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
return output
|
37
|
+
end
|
38
|
+
|
39
|
+
def ts_ajax_handler
|
40
|
+
@_ts_ajax_handler ||= Handler.new(tablesorter_params)
|
41
|
+
end
|
42
|
+
|
43
|
+
def tablesorter_params
|
44
|
+
params.permit(:page, :size, :controller, :action, :query, :sort, :filter,
|
45
|
+
{ sort: params[:sort].try(:keys) },
|
46
|
+
{ filter: params[:filter].try(:keys) })
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module JqueryTablesorter
|
2
|
+
module RailsUtils
|
3
|
+
module Ajax
|
4
|
+
# Represents a table sorting Filter. In most cases this is also a column
|
5
|
+
# in your table, but might als be a global/external filter.
|
6
|
+
class Filter
|
7
|
+
# Name of the column in the DB. Used for queries, but may also be :all for glob. filters.
|
8
|
+
attr_accessor :column_name
|
9
|
+
# Class of the base model.
|
10
|
+
attr_accessor :model
|
11
|
+
# If you need to join, this is your relation table
|
12
|
+
attr_accessor :join_rel
|
13
|
+
# An external table column to be used with join.
|
14
|
+
attr_accessor :external_column
|
15
|
+
# If a having clase is required, pass it here. This will change the controll flow on
|
16
|
+
# filter-/sorting.
|
17
|
+
attr_accessor :having_clause
|
18
|
+
# Optional data type of the column. This might be used to make queries more flexible.
|
19
|
+
# For examaple, if DateTime is passed, it will strip away milliseconds from query.
|
20
|
+
attr_accessor :data_type
|
21
|
+
# Optional boolean filter if the given filter is a global filter or not.
|
22
|
+
attr_accessor :global_filter
|
23
|
+
# Optional index requested by tablesorter, needed for glob. filters.
|
24
|
+
attr_accessor :position
|
25
|
+
# Optional block to modify the real input of filters to match UI (e.g. Input: 'Iceland' => DB: 'is')
|
26
|
+
# This block has to return an array which will be used for an IN-Query. Thus, the current implementation
|
27
|
+
# depends on an 1:1 match.
|
28
|
+
attr_accessor :filter_mapping
|
29
|
+
|
30
|
+
def initialize(column_name, model_clazz, opts = {})
|
31
|
+
@column_name = column_name
|
32
|
+
@model = model_clazz
|
33
|
+
@position = opts[:position]
|
34
|
+
@join_rel = opts[:join_rel]
|
35
|
+
@external_column = opts[:external_column]
|
36
|
+
@having_clause = opts[:having_clause]
|
37
|
+
@data_type = opts[:data_type]
|
38
|
+
@global_filter = opts[:global_filter]
|
39
|
+
@filter_mapping = opts[:filter_mapping]
|
40
|
+
end
|
41
|
+
|
42
|
+
def global_filter?
|
43
|
+
@global_filter || false
|
44
|
+
end
|
45
|
+
|
46
|
+
def name
|
47
|
+
self.column_name
|
48
|
+
end
|
49
|
+
|
50
|
+
def model_class
|
51
|
+
self.model
|
52
|
+
end
|
53
|
+
|
54
|
+
def external?
|
55
|
+
external_column.present?
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,248 @@
|
|
1
|
+
module JqueryTablesorter
|
2
|
+
module RailsUtils
|
3
|
+
module Ajax
|
4
|
+
# Class used by ActionController concern. Encapsulates query logic.
|
5
|
+
# For further documentation see ajax-module.
|
6
|
+
class Handler
|
7
|
+
|
8
|
+
def initialize(tablesorter_params)
|
9
|
+
@ts_params = tablesorter_params
|
10
|
+
end
|
11
|
+
|
12
|
+
# Define the table structure
|
13
|
+
def create_filter_info(column_name, model_clazz, filter_opts = {})
|
14
|
+
filter = Filter.new(column_name, model_clazz, filter_opts)
|
15
|
+
ajax_filters << filter
|
16
|
+
return filter
|
17
|
+
end
|
18
|
+
|
19
|
+
# Load data for the given tablesorter params in a controller action
|
20
|
+
# Params:
|
21
|
+
# base_query: If there are any relevant joins or so -> pass the AR relation here
|
22
|
+
# Returns a hash with:
|
23
|
+
# total_rows: How many records are there available
|
24
|
+
# filtered_rows: How many records are left after filtering
|
25
|
+
# records: An collection with the resulting records
|
26
|
+
def query_data(base_query)
|
27
|
+
@query = base_query
|
28
|
+
|
29
|
+
result = Hash.new
|
30
|
+
|
31
|
+
# Filters
|
32
|
+
@query = apply_filters(@query, tablesorter_params)
|
33
|
+
|
34
|
+
# Calculate row counts
|
35
|
+
rec_counts = record_counts(base_query, @query)
|
36
|
+
result[:filtered_rows] = rec_counts[:filtered_rows]
|
37
|
+
result[:total_rows] = rec_counts[:total_rows]
|
38
|
+
|
39
|
+
# Handle paging afterwards
|
40
|
+
@query = handle_pagination(@query, tablesorter_params, result)
|
41
|
+
|
42
|
+
# Sorting
|
43
|
+
@query = apply_sorting(@query, tablesorter_params)
|
44
|
+
|
45
|
+
result[:records] = @query
|
46
|
+
|
47
|
+
return result
|
48
|
+
end
|
49
|
+
|
50
|
+
# Calulate count of all and filtered records
|
51
|
+
# Params:
|
52
|
+
# model_query: The base query of the current selection
|
53
|
+
# filtered_query: The filtered query (relation with applied tablesorter filters)
|
54
|
+
def record_counts(model_query, filtered_query)
|
55
|
+
counts = Hash.new
|
56
|
+
total = model_query.distinct.count(:id)
|
57
|
+
|
58
|
+
if total.is_a?(Hash) # Handle results of joined queries. This feels a little bit hacky.
|
59
|
+
total = total.keys.length
|
60
|
+
end
|
61
|
+
|
62
|
+
counts[:total_rows] = total
|
63
|
+
|
64
|
+
if tablesorter_params[:filter]
|
65
|
+
# Count again if additional filters were applied (fires a query)
|
66
|
+
cnt = filtered_query.count("#{model_query.table_name}.id")
|
67
|
+
|
68
|
+
if cnt.is_a?(Hash) # Handle results of having-queries. This feels a little bit hacky.
|
69
|
+
cnt = cnt.keys.length
|
70
|
+
end
|
71
|
+
counts[:filtered_rows] = cnt
|
72
|
+
else
|
73
|
+
counts[:filtered_rows] = total # There wasn't any reduction.
|
74
|
+
end
|
75
|
+
|
76
|
+
return counts
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
# let every special case be handled within that block.
|
81
|
+
# block should remove the values from the params parameter to allow regular processing.
|
82
|
+
def apply_filters(record_relation, filter_params)
|
83
|
+
splat_global_filter(filter_params)
|
84
|
+
record_relation = apply_global_filters(record_relation, filter_params)
|
85
|
+
|
86
|
+
# iterate over all filter inputs
|
87
|
+
(filter_params[:filter] || {}).each do |filter_index, filter_value|
|
88
|
+
sel_col = ajax_filters[filter_index.to_i]
|
89
|
+
next if sel_col.blank?
|
90
|
+
|
91
|
+
clazz = sel_col.model
|
92
|
+
selected_column = sel_col.name
|
93
|
+
|
94
|
+
if sel_col.external? # query an external model
|
95
|
+
ext_query = "LOWER(#{sel_col.join_rel}.#{sel_col.external_column}::varchar) LIKE LOWER(?)"
|
96
|
+
record_relation = record_relation.where(ext_query, "%#{filter_value}%")
|
97
|
+
|
98
|
+
elsif sel_col.having_clause
|
99
|
+
clause = sel_col.having_clause
|
100
|
+
record_relation = record_relation.having("LOWER((#{clause})::varchar) LIKE ?", "%#{filter_value}%")
|
101
|
+
|
102
|
+
elsif sel_col.filter_mapping # there were modifications on the query
|
103
|
+
target_col = "#{clazz.table_name}.#{selected_column}"
|
104
|
+
values = sel_col.filter_mapping.call(filter_value)
|
105
|
+
# Maybe we could use an SIMILAR TO query for this.
|
106
|
+
record_relation = record_relation.where("LOWER(#{target_col}::varchar) IN (?)", values )
|
107
|
+
|
108
|
+
else # directly on current model
|
109
|
+
target_col = "#{clazz.table_name}.#{selected_column}"
|
110
|
+
if sel_col.data_type == DateTime
|
111
|
+
target_col = "date_trunc('minute', #{target_col})"
|
112
|
+
end
|
113
|
+
record_relation = record_relation.where("LOWER(#{target_col}::varchar) LIKE LOWER(?)", "%#{filter_value}%" )
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
return record_relation
|
119
|
+
end
|
120
|
+
|
121
|
+
# Sort the passed relation by the tablesorter-sorting.
|
122
|
+
def apply_sorting(record_relation, sort_params)
|
123
|
+
(sort_params[:sort] || {}).each do |sort_index, order|
|
124
|
+
order = (order.to_i % 2 == 0) ? :asc : :desc
|
125
|
+
sel_col = ajax_filters[sort_index.to_i]
|
126
|
+
|
127
|
+
if sel_col.external?
|
128
|
+
order_query = [sel_col.join_rel, sel_col.external_column].compact.join('.')
|
129
|
+
record_relation = record_relation.order("#{order_query} #{order}")
|
130
|
+
|
131
|
+
elsif sel_col.having_clause
|
132
|
+
# If there is a having_clause, use the column name w/o tablename
|
133
|
+
record_relation = record_relation.order("#{sel_col.name} #{order} NULLS LAST")
|
134
|
+
|
135
|
+
else
|
136
|
+
order_query = [sel_col.model.table_name, sel_col.name].compact.join('.')
|
137
|
+
record_relation = record_relation.order("#{order_query} #{order} NULLS LAST")
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
return record_relation
|
143
|
+
end
|
144
|
+
|
145
|
+
# Paginiation/the amount of visible rows in the table (per page)
|
146
|
+
def handle_pagination(query, ts_params, result)
|
147
|
+
# Tablesorter submits row count or simply 'all'. If user requests more rows
|
148
|
+
# than available do nothing.
|
149
|
+
return query if ( (ts_params[:size] == 'all') || (ts_params[:size].to_i >= result[:total_rows]) )
|
150
|
+
|
151
|
+
query = query
|
152
|
+
.limit(ts_params[:size].to_i)
|
153
|
+
.offset(ts_params[:size].to_i * ts_params[:page].to_i)
|
154
|
+
|
155
|
+
return query
|
156
|
+
end
|
157
|
+
|
158
|
+
# Array with all currently configured Filter-Objects
|
159
|
+
def ajax_filters
|
160
|
+
@_ajax_table_filters ||= []
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
def tablesorter_params
|
166
|
+
@ts_params
|
167
|
+
end
|
168
|
+
|
169
|
+
# Iterate over all columns with the (previous in *splat_global_filter* initialized)
|
170
|
+
# global filter value
|
171
|
+
def apply_global_filters(record_relation, filter_params)
|
172
|
+
# TODO Wouldn't it be smarter to make query an array and join it by ' OR '?
|
173
|
+
query = ''
|
174
|
+
filter_values = []
|
175
|
+
|
176
|
+
(filter_params[:global_filter] || {}).each do |filter_index, filter_value|
|
177
|
+
sel_col = ajax_filters[filter_index.to_i]
|
178
|
+
next if sel_col.blank?
|
179
|
+
|
180
|
+
clazz = sel_col.model
|
181
|
+
selected_column = sel_col.name
|
182
|
+
table_name = clazz.table_name
|
183
|
+
|
184
|
+
if sel_col.external? # Query an external model
|
185
|
+
query << "LOWER(#{sel_col.join_rel}.#{sel_col.external_column}::varchar) LIKE LOWER(?) OR "
|
186
|
+
filter_values << "%#{filter_value}%"
|
187
|
+
|
188
|
+
elsif sel_col.filter_mapping # there were modifications on the query
|
189
|
+
target_col = "#{clazz.table_name}.#{selected_column}"
|
190
|
+
values = sel_col.filter_mapping.call(filter_value)
|
191
|
+
# Maybe we could use an SIMILAR TO query for this.
|
192
|
+
query << "LOWER(#{target_col}::varchar) IN (?) OR "
|
193
|
+
filter_values << values
|
194
|
+
|
195
|
+
elsif sel_col.having_clause
|
196
|
+
# Having clauses will create an extra query to select IDs of base-table records
|
197
|
+
# an add them into the main query as IN <ids>.
|
198
|
+
# If there is a having_clause, use the column name only w/o tablename.
|
199
|
+
clause = "LOWER(#{sel_col.having_clause}::varchar) LIKE LOWER(?)"
|
200
|
+
filter_values << record_relation.having(clause, "%#{filter_value}%")
|
201
|
+
.pluck(:id)
|
202
|
+
query << "#{table_name}.id IN (?) OR "
|
203
|
+
|
204
|
+
else
|
205
|
+
target_col = "#{table_name}.#{selected_column}"
|
206
|
+
|
207
|
+
if sel_col.data_type == DateTime # Special handling for Dates -> strip away millisecs
|
208
|
+
target_col = "date_trunc('second', #{target_col})"
|
209
|
+
end
|
210
|
+
|
211
|
+
query << "LOWER(#{target_col}::varchar) LIKE LOWER(?) OR "
|
212
|
+
filter_values << "%#{filter_value}%"
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
query = query.chomp(' OR ') # remove the last OR
|
217
|
+
|
218
|
+
return record_relation.where(query, *filter_values)
|
219
|
+
|
220
|
+
end
|
221
|
+
|
222
|
+
# If any global filter value (the user input) is found (which currently is asumed to the last),
|
223
|
+
# take this input and add it to a global_filter subkey with the corresponding index of each
|
224
|
+
# not global-filter column. Thus, later the may be used to check all coulmns for the given
|
225
|
+
# input.
|
226
|
+
def splat_global_filter(filter_params)
|
227
|
+
# Global filter params is assumed to be at the last index
|
228
|
+
global_filter = ajax_filters.find { |c| c.global_filter? }
|
229
|
+
return unless global_filter
|
230
|
+
|
231
|
+
global_filter_value = filter_params.dig(:filter, global_filter.position.to_s)
|
232
|
+
return if global_filter_value.nil?
|
233
|
+
|
234
|
+
filter_params[:global_filter] ||= {}
|
235
|
+
ajax_filters.each_with_index do |col, idx|
|
236
|
+
next if (col.nil? || col.global_filter?)
|
237
|
+
# Add search query for each (non-global) value
|
238
|
+
filter_params[:global_filter][idx.to_s] = global_filter_value
|
239
|
+
end
|
240
|
+
|
241
|
+
# Remove the global filter from the params
|
242
|
+
filter_params[:filter].delete(global_filter.position.to_s)
|
243
|
+
end
|
244
|
+
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jquery-tablesorter-rails-utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Erik-B. Ernst
|
8
|
+
- Thomas Halter
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2016-09-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '4.0'
|
21
|
+
- - "<"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '6.0'
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '4.0'
|
31
|
+
- - "<"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '6.0'
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: activesupport
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '4.0'
|
41
|
+
- - "<"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '6.0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '4.0'
|
51
|
+
- - "<"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '6.0'
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: actionview
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '4.0'
|
61
|
+
- - "<"
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: '6.0'
|
64
|
+
type: :runtime
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '4.0'
|
71
|
+
- - "<"
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '6.0'
|
74
|
+
- !ruby/object:Gem::Dependency
|
75
|
+
name: pg
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
type: :runtime
|
82
|
+
prerelease: false
|
83
|
+
version_requirements: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - ">="
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
- !ruby/object:Gem::Dependency
|
89
|
+
name: bundler
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - "~>"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '1.13'
|
95
|
+
type: :development
|
96
|
+
prerelease: false
|
97
|
+
version_requirements: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - "~>"
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '1.13'
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: rake
|
104
|
+
requirement: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - "~>"
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '10.0'
|
109
|
+
type: :development
|
110
|
+
prerelease: false
|
111
|
+
version_requirements: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - "~>"
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '10.0'
|
116
|
+
description: Some helpers to work with jQuery tablesorter and Ruby on Rails.
|
117
|
+
email:
|
118
|
+
- github@black-milk.de
|
119
|
+
executables: []
|
120
|
+
extensions: []
|
121
|
+
extra_rdoc_files: []
|
122
|
+
files:
|
123
|
+
- CHANGELOG.md
|
124
|
+
- Gemfile
|
125
|
+
- LICENSE
|
126
|
+
- README.md
|
127
|
+
- Rakefile
|
128
|
+
- jquery-tablesorter-rails-utils.gemspec
|
129
|
+
- lib/jquery-tablesorter-rails-utils.rb
|
130
|
+
- lib/jquery-tablesorter/rails-utils/ajax.rb
|
131
|
+
- lib/jquery-tablesorter/rails-utils/ajax/action_controller.rb
|
132
|
+
- lib/jquery-tablesorter/rails-utils/ajax/filter.rb
|
133
|
+
- lib/jquery-tablesorter/rails-utils/ajax/handler.rb
|
134
|
+
- lib/jquery-tablesorter/rails-utils/version.rb
|
135
|
+
homepage: https://github.com/themilkman/jquery-tablesorter-rails-utils
|
136
|
+
licenses:
|
137
|
+
- MIT
|
138
|
+
metadata: {}
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: 1.9.3
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 2.5.1
|
156
|
+
signing_key:
|
157
|
+
specification_version: 4
|
158
|
+
summary: Some helpers to work with jQuery tablesorter and Ruby on Rails
|
159
|
+
test_files: []
|