magic_grid 0.9.2
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +19 -0
- data/Rakefile +44 -0
- data/lib/assets/javascripts/magic_grid.js +154 -0
- data/lib/locales/en.yml +7 -0
- data/lib/magic_grid.rb +7 -0
- data/lib/magic_grid/definition.rb +212 -0
- data/lib/magic_grid/engine.rb +14 -0
- data/lib/magic_grid/helpers.rb +243 -0
- data/lib/magic_grid/railtie.rb +9 -0
- data/lib/magic_grid/version.rb +3 -0
- data/lib/tasks/magic_grid_tasks.rake +4 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +9 -0
- data/test/dummy/app/assets/javascripts/posts.js +8 -0
- data/test/dummy/app/assets/javascripts/users.js +2 -0
- data/test/dummy/app/assets/stylesheets/application.css +7 -0
- data/test/dummy/app/assets/stylesheets/posts.css +4 -0
- data/test/dummy/app/assets/stylesheets/scaffold.css +56 -0
- data/test/dummy/app/assets/stylesheets/users.css +4 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/posts_controller.rb +104 -0
- data/test/dummy/app/controllers/users_controller.rb +84 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/posts_helper.rb +2 -0
- data/test/dummy/app/helpers/users_helper.rb +2 -0
- data/test/dummy/app/models/post.rb +6 -0
- data/test/dummy/app/models/user.rb +4 -0
- data/test/dummy/app/views/layouts/application.html.erb +19 -0
- data/test/dummy/app/views/posts/_form.html.erb +33 -0
- data/test/dummy/app/views/posts/by_user.html.erb +18 -0
- data/test/dummy/app/views/posts/edit.html.erb +6 -0
- data/test/dummy/app/views/posts/index.html.erb +76 -0
- data/test/dummy/app/views/posts/new.html.erb +5 -0
- data/test/dummy/app/views/posts/show.html.erb +25 -0
- data/test/dummy/app/views/users/_form.html.erb +25 -0
- data/test/dummy/app/views/users/edit.html.erb +6 -0
- data/test/dummy/app/views/users/index.html.erb +42 -0
- data/test/dummy/app/views/users/new.html.erb +5 -0
- data/test/dummy/app/views/users/show.html.erb +15 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +59 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +40 -0
- data/test/dummy/config/environments/production.rb +67 -0
- data/test/dummy/config/environments/test.rb +37 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +15 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +68 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20111025191809_create_users.rb +10 -0
- data/test/dummy/db/migrate/20111025195229_create_posts.rb +13 -0
- data/test/dummy/db/schema.rb +34 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +49565 -0
- data/test/dummy/log/passenger.3000.log +362 -0
- data/test/dummy/log/test.log +77 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/test/dummy/public/css/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/test/dummy/public/css/smoothness/jquery-ui-1.8.18.custom.css +565 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/test/fixtures/posts.yml +23 -0
- data/test/dummy/test/fixtures/users.yml +15 -0
- data/test/dummy/test/functional/posts_controller_test.rb +49 -0
- data/test/dummy/test/functional/users_controller_test.rb +50 -0
- data/test/dummy/test/integration/spider_test.rb +27 -0
- data/test/dummy/test/unit/helpers/posts_helper_test.rb +4 -0
- data/test/dummy/test/unit/helpers/users_helper_test.rb +4 -0
- data/test/dummy/test/unit/post_test.rb +7 -0
- data/test/dummy/test/unit/user_test.rb +7 -0
- data/test/magic_grid_test.rb +11 -0
- data/test/test_helper.rb +17 -0
- metadata +333 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
= MagicGrid
|
2
|
+
|
3
|
+
Takes a collection and creates a paginated table of using a supplied column definition.
|
4
|
+
|
5
|
+
== Basic Usage
|
6
|
+
|
7
|
+
In your +Gemfile+:
|
8
|
+
|
9
|
+
gem 'magic_grid', :git => 'git://github.com/rmg/magic_grid.git'
|
10
|
+
|
11
|
+
In your view:
|
12
|
+
|
13
|
+
<%= magic_grid(@posts, [:title, :author]) %>
|
14
|
+
|
15
|
+
|
16
|
+
== Development
|
17
|
+
|
18
|
+
To test, <code>(cd test/dummy && rake RAILS_ENV=test db:create db:migrate) && rake test</code>
|
19
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'MagicGrid'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:tests) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
require 'rspec/core/rake_task'
|
37
|
+
|
38
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
39
|
+
t.pattern = 'spec/**/*_spec.rb'
|
40
|
+
t.verbose = false
|
41
|
+
end
|
42
|
+
|
43
|
+
task :test => [:spec, :tests]
|
44
|
+
task :default => :test
|
@@ -0,0 +1,154 @@
|
|
1
|
+
// vim: ts=4 et sw=4 sts=4
|
2
|
+
|
3
|
+
$(function () {
|
4
|
+
// Micro-plugin for positioning the cursor
|
5
|
+
$.fn.setCursor = $.fn.setCursor || function(pos) {
|
6
|
+
return this.each(function() {
|
7
|
+
if (this.setSelectionRange) {
|
8
|
+
this.focus();
|
9
|
+
this.setSelectionRange(pos, pos);
|
10
|
+
} else if (this.createTextRange) {
|
11
|
+
var range = this.createTextRange();
|
12
|
+
range.collapse(true);
|
13
|
+
range.moveEnd('character', pos);
|
14
|
+
range.moveStart('character', pos);
|
15
|
+
range.select();
|
16
|
+
}
|
17
|
+
});
|
18
|
+
};
|
19
|
+
|
20
|
+
// Micro-plugin for getting the position of the cursor
|
21
|
+
$.fn.getCursor = $.fn.getCursor || function () {
|
22
|
+
// IE doesn't have selectionStart, and I'm too lazy to implement
|
23
|
+
// the IE specific version of this, so we'll just assume
|
24
|
+
// the cursor is at the end of the input for this case.
|
25
|
+
if (typeof this[0].selectionStart === 'undefined') {
|
26
|
+
return this.value.length;
|
27
|
+
} else {
|
28
|
+
return this[0].selectionStart;
|
29
|
+
}
|
30
|
+
};
|
31
|
+
|
32
|
+
// Micro-plugin for collecting all the listener and search inputs
|
33
|
+
$.fn.getGridParams = $.fn.getGridParams || function (extras) {
|
34
|
+
var listeners = this.data("listeners"),
|
35
|
+
params = $.extend({}, {'magic_grid_id' : this.attr('id')}, extras || {}),
|
36
|
+
$input, param_key, listened_id;
|
37
|
+
for (listened_id in listeners) {
|
38
|
+
param_key = listeners[listened_id];
|
39
|
+
$input = $("#" + listened_id);
|
40
|
+
if ($input.is(":checkbox")) {
|
41
|
+
params[param_key] = $input.is(":checked");
|
42
|
+
} else if ($input.is("select")) {
|
43
|
+
params[param_key] = $input.find("option:selected").val();
|
44
|
+
} else {
|
45
|
+
params[param_key] = $input.val();
|
46
|
+
}
|
47
|
+
}
|
48
|
+
if (this.is("[data-searcher]")) {
|
49
|
+
params[this.attr('id') + '_q'] = $("#" + this.data("searcher")).val();
|
50
|
+
}
|
51
|
+
return $.extend({}, params);
|
52
|
+
}
|
53
|
+
|
54
|
+
// Default handler for ajax events that displays 'Loading...' in
|
55
|
+
// the head of the table.
|
56
|
+
$(".magic_grid[data-default-ajax-handler=true]").on("magic_grid:loading", function (e) {
|
57
|
+
$(".magic_grid_spinner", this).
|
58
|
+
addClass("ui-icon-spinner").
|
59
|
+
html("<em>Loading...</em>");
|
60
|
+
});
|
61
|
+
|
62
|
+
$(".magic_grid[data-remote=true]").on( "click", ".pagination a, .sorter a", function (e) {
|
63
|
+
var $grid = $(e.delegateTarget),
|
64
|
+
url = this.href;
|
65
|
+
$grid.trigger("magic_grid:loading");
|
66
|
+
$grid.load(url + ' #' + $grid.attr('id') + " > *", function () {
|
67
|
+
$grid.trigger("magic_grid:loaded");
|
68
|
+
});
|
69
|
+
return false;
|
70
|
+
});
|
71
|
+
|
72
|
+
$(".magic_grid[data-searcher]").each( function () {
|
73
|
+
var $grid = $(this),
|
74
|
+
grid_id = this.id,
|
75
|
+
input_id = "#" + $grid.data("searcher"),
|
76
|
+
live = $grid.data("live-search"),
|
77
|
+
// keydown seems to be the only reliable and portable way to capture
|
78
|
+
// things like backspace and delete
|
79
|
+
events = (live ? "keydown change search" : "change search"),
|
80
|
+
timer = null,
|
81
|
+
internal = ($grid.has(input_id).length > 0),
|
82
|
+
listener = (internal ? $grid : $(input_id).parent()),
|
83
|
+
minLength = $(input_id).data("min-length") || 3;
|
84
|
+
listener.on(events, input_id, function (e) {
|
85
|
+
var is_manual = (e.type == 'search' ||
|
86
|
+
e.type == 'change' ||
|
87
|
+
(e.type == 'keydown' && e.which == '13')),
|
88
|
+
base_url = $grid.data("current") || "",
|
89
|
+
//40 wpm typists == 280ms/keystroke
|
90
|
+
//90 wpm typists == 120ms/keystroke
|
91
|
+
delay = is_manual ? 1 : (parseInt(live) || 500);
|
92
|
+
clearTimeout(timer);
|
93
|
+
timer = setTimeout(function () {
|
94
|
+
var $input = $(input_id),
|
95
|
+
current = $input.data("current"),
|
96
|
+
value = $input.val(),
|
97
|
+
length = value.length,
|
98
|
+
url = base_url + "?",
|
99
|
+
relevant = is_manual || (value != current && (length >= minLength || length == 0)),
|
100
|
+
pos = $input.getCursor();
|
101
|
+
clearTimeout(timer);
|
102
|
+
url += $.param($grid.getGridParams());
|
103
|
+
if (relevant) {
|
104
|
+
$grid.trigger("magic_grid:loading");
|
105
|
+
if ($grid.data("remote")) {
|
106
|
+
if (internal && live && !is_manual) {
|
107
|
+
$(input_id).prop('disabled', true);
|
108
|
+
}
|
109
|
+
$grid.load(url + ' #' + grid_id + ' > *', function () {
|
110
|
+
// Move the cursor back to where it was,
|
111
|
+
// less surprising that way.
|
112
|
+
// EXCEPT FOR IE, that is
|
113
|
+
$grid.trigger("magic_grid:loaded");
|
114
|
+
if (internal) {
|
115
|
+
$(input_id).setCursor(pos);
|
116
|
+
}
|
117
|
+
});
|
118
|
+
} else {
|
119
|
+
window.location = url;
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}, delay);
|
123
|
+
});
|
124
|
+
});
|
125
|
+
|
126
|
+
$(".magic_grid[data-listeners]").each( function () {
|
127
|
+
var $grid = $(this),
|
128
|
+
listeners = $grid.data("listeners"),
|
129
|
+
grid_id = this.id
|
130
|
+
base_url = $grid.data("current"),
|
131
|
+
handler = function (change) {
|
132
|
+
var url = base_url + "?" + $.param($grid.getGridParams());
|
133
|
+
$grid.trigger("magic_grid:loading");
|
134
|
+
if ($grid.data("remote")) {
|
135
|
+
$grid.load(url + ' #' + grid_id + " > *", function () {
|
136
|
+
$grid.trigger("magic_grid:loaded");
|
137
|
+
});
|
138
|
+
} else {
|
139
|
+
window.location = url;
|
140
|
+
}
|
141
|
+
};
|
142
|
+
for (var k in listeners) {
|
143
|
+
if ($("#" + k).hasClass("ready")) {
|
144
|
+
$("#" + k).on("change", {"field": listeners[k]}, handler);
|
145
|
+
} else {
|
146
|
+
$("#" + k).on("ready", {"field": listeners[k]}, function (ready) {
|
147
|
+
$(this).on("change", ready.data, handler);
|
148
|
+
});
|
149
|
+
}
|
150
|
+
}
|
151
|
+
});
|
152
|
+
|
153
|
+
$(".magic_grid").trigger("magic_grid:loaded");
|
154
|
+
});
|
data/lib/locales/en.yml
ADDED
data/lib/magic_grid.rb
ADDED
@@ -0,0 +1,212 @@
|
|
1
|
+
require 'will_paginate/view_helpers/action_view'
|
2
|
+
|
3
|
+
module MagicGrid
|
4
|
+
class Definition
|
5
|
+
include WillPaginate::ActionView
|
6
|
+
attr_accessor :columns, :collection, :magic_id, :options, :params, :accepted,
|
7
|
+
:current_sort_col, :current_order, :default_order
|
8
|
+
|
9
|
+
DEFAULTS = {
|
10
|
+
:class => [],
|
11
|
+
:top_pager => false,
|
12
|
+
:bottom_pager => true,
|
13
|
+
:remote => false,
|
14
|
+
:per_page => 30,
|
15
|
+
:searchable => false,
|
16
|
+
:search_method => :search,
|
17
|
+
:min_search_length => 3,
|
18
|
+
:id => false,
|
19
|
+
:searcher => false,
|
20
|
+
:needs_searcher => false,
|
21
|
+
:live_search => false,
|
22
|
+
:current_search => nil,
|
23
|
+
:listeners => {},
|
24
|
+
:listener_handler => nil,
|
25
|
+
:default_col => 0,
|
26
|
+
:default_order => :asc,
|
27
|
+
:empty_header => false,
|
28
|
+
:empty_footer => false,
|
29
|
+
:post_filter => false,
|
30
|
+
:collection_post_filter? => true,
|
31
|
+
:default_ajax_handler => true,
|
32
|
+
:search_button => false,
|
33
|
+
:searcher_size => nil,
|
34
|
+
}
|
35
|
+
|
36
|
+
def self.runtime_defaults
|
37
|
+
# run these lazily to catch any late I18n path changes
|
38
|
+
DEFAULTS.merge(
|
39
|
+
:if_empty => I18n.t("magic_grid.no_results").capitalize, # "No results found."
|
40
|
+
:searcher_label => I18n.t("magic_grid.search.label").capitalize + ': ', # "Search: "
|
41
|
+
:searcher_tooltip =>I18n.t("magic_grid.search.tooltip"), # "type.. + <return>"
|
42
|
+
:searcher_button =>I18n.t("magic_grid.search.button").capitalize, # "Search"
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(cols_or_opts, collection = nil, controller = nil, opts = {})
|
47
|
+
if cols_or_opts.is_a? Hash
|
48
|
+
@options = self.class.runtime_defaults.merge(cols_or_opts.reject {|k| k == :cols})
|
49
|
+
@columns = cols_or_opts.fetch(:cols, [])
|
50
|
+
elsif cols_or_opts.is_a? Array
|
51
|
+
@options = self.class.runtime_defaults.merge opts
|
52
|
+
@columns = cols_or_opts
|
53
|
+
else
|
54
|
+
raise "I have no idea what that is, but it's not a Hash or an Array"
|
55
|
+
end
|
56
|
+
@default_order = @options[:default_order]
|
57
|
+
@params = controller.try(:params) || {}
|
58
|
+
@collection = collection
|
59
|
+
begin
|
60
|
+
#if @collection.respond_to? :table
|
61
|
+
table_name = @collection.quoted_table_name
|
62
|
+
table_columns = @collection.table.columns.map {|c| c.name}
|
63
|
+
rescue
|
64
|
+
Rails.logger.debug "Given collection doesn't respond to :table well"
|
65
|
+
table_name = nil
|
66
|
+
table_columns = @columns.each_index.to_a
|
67
|
+
end
|
68
|
+
i = 0
|
69
|
+
hash = []
|
70
|
+
@columns.map! do |c|
|
71
|
+
if c.is_a? Symbol
|
72
|
+
c = {:col => c}
|
73
|
+
elsif c.is_a? String
|
74
|
+
c = {:label => c}
|
75
|
+
end
|
76
|
+
c[:id] = i
|
77
|
+
i += 1
|
78
|
+
if c.key?(:col) and c[:col].is_a?(Symbol) and table_columns.include?(c[:col])
|
79
|
+
c[:sql] = "#{table_name}.#{@collection.connection.quote_column_name(c[:col].to_s)}" unless c.key?(:sql)
|
80
|
+
end
|
81
|
+
c[:label] = c[:col].to_s.titleize if not c.key? :label
|
82
|
+
hash << c[:label]
|
83
|
+
c
|
84
|
+
end
|
85
|
+
if @options[:id]
|
86
|
+
@magic_id = @options[:id]
|
87
|
+
else
|
88
|
+
@magic_id = hash.join.hash.abs.to_s(36)
|
89
|
+
@magic_id << @collection.to_sql.hash.abs.to_s(36) if @collection.respond_to? :to_sql
|
90
|
+
end
|
91
|
+
@current_sort_col = sort_col_i = param(:col, @options[:default_col]).to_i
|
92
|
+
if @collection.respond_to?(:order) and @columns.count > sort_col_i and @columns[sort_col_i].has_key?(:sql)
|
93
|
+
sort_col = @columns[sort_col_i][:sql]
|
94
|
+
@current_order = order(param(:order, @default_order))
|
95
|
+
sort_dir = order_sql(@current_order)
|
96
|
+
@collection = @collection.order("#{sort_col} #{sort_dir}")
|
97
|
+
else
|
98
|
+
Rails.logger.debug "#{self.class.name}: Ignoring sorting on non-AR collection"
|
99
|
+
end
|
100
|
+
|
101
|
+
@options[:searchable] = [] if @options[:searchable] and not @options[:searchable].kind_of? Array
|
102
|
+
|
103
|
+
@accepted = [:action, :controller, param_key(:page)]
|
104
|
+
@accepted << param_key(:q) if @options[:searchable]
|
105
|
+
@accepted += @options[:listeners].values
|
106
|
+
|
107
|
+
if @collection.respond_to?(:where) or @options[:listener_handler].respond_to?(:call)
|
108
|
+
if @options[:listener_handler].respond_to? :call
|
109
|
+
@collection = @options[:listener_handler].call(@collection)
|
110
|
+
else
|
111
|
+
@options[:listeners].each_pair do |key, value|
|
112
|
+
if @params[value] and not @params[value].to_s.empty?
|
113
|
+
@collection = @collection.where(key => @params[value])
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
else
|
118
|
+
unless @options[:listeners].empty?
|
119
|
+
Rails.logger.warn "#{self.class.name}: Ignoring listener on dumb collection"
|
120
|
+
@options[:listeners] = {}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
@options[:current_search] ||= param(:q)
|
124
|
+
if (@collection.respond_to?(:where) or
|
125
|
+
(@options[:search_method] and @collection.respond_to?(@options[:search_method])))
|
126
|
+
if param(:q) and not param(:q).empty? and @options[:searchable]
|
127
|
+
orig_collection = @collection
|
128
|
+
begin
|
129
|
+
@collection = @collection.__send__(@options[:search_method], param(:q))
|
130
|
+
rescue
|
131
|
+
Rails.logger.debug "Given collection doesn't respond to #{@options[:search_method]} well"
|
132
|
+
@collection = orig_collection
|
133
|
+
search_cols = @options[:searchable].map do |searchable|
|
134
|
+
case searchable
|
135
|
+
when Symbol
|
136
|
+
known = @columns.find {|col| col[:col] == searchable}
|
137
|
+
if known and known.key?(:sql)
|
138
|
+
known[:sql]
|
139
|
+
else
|
140
|
+
"#{table_name}.#{@collection.connection.quote_column_name(searchable.to_s)}"
|
141
|
+
end
|
142
|
+
when Integer
|
143
|
+
@columns[searchable][:sql]
|
144
|
+
when String
|
145
|
+
searchable
|
146
|
+
else
|
147
|
+
raise "Searchable must be identifiable"
|
148
|
+
end
|
149
|
+
end
|
150
|
+
unless search_cols.empty?
|
151
|
+
begin
|
152
|
+
clauses = search_cols.map {|c| c << " LIKE :search" }.join(" OR ")
|
153
|
+
@collection = @collection.where(clauses, {:search => "%#{param(:q)}%"})
|
154
|
+
rescue
|
155
|
+
Rails.logger.debug "Given collection doesn't respond to :where well"
|
156
|
+
@collection = orig_collection
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
else
|
162
|
+
if @options[:searchable] or param(:q)
|
163
|
+
Rails.logger.warn "#{self.class.name}: Ignoring searchable fields on non-AR collection"
|
164
|
+
end
|
165
|
+
@options[:searchable] = false
|
166
|
+
end
|
167
|
+
if not @options[:searcher] and @options[:searchable]
|
168
|
+
@options[:needs_searcher] = true
|
169
|
+
@options[:searcher] = param_key(:searcher)
|
170
|
+
end
|
171
|
+
# Do collection filter first, may convert from AR to Array
|
172
|
+
if @options[:collection_post_filter?] and @collection.respond_to?(:post_filter)
|
173
|
+
@collection = @collection.post_filter(controller)
|
174
|
+
end
|
175
|
+
if @options[:post_filter] and @options[:post_filter].respond_to?(:call)
|
176
|
+
@collection = @options[:post_filter].call(@collection)
|
177
|
+
end
|
178
|
+
# Paginate at the very end, after all sorting, filtering, etc..
|
179
|
+
if @options[:per_page]
|
180
|
+
@collection = @collection.paginate(:page => param(:page, 1),
|
181
|
+
:per_page => @options[:per_page])
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
def param_key(key)
|
186
|
+
"#{@magic_id}_#{key}".to_sym
|
187
|
+
end
|
188
|
+
|
189
|
+
def param(key, default=nil)
|
190
|
+
@params.fetch(param_key(key), default)
|
191
|
+
end
|
192
|
+
|
193
|
+
def base_params
|
194
|
+
@params.select { |k,_| accepted.include? k.to_sym }.merge :magic_grid_id => @magic_id
|
195
|
+
end
|
196
|
+
|
197
|
+
def order(something)
|
198
|
+
case something
|
199
|
+
when 1, "1", :desc, :DESC, "desc", "DESC"
|
200
|
+
1
|
201
|
+
#when 0, "0", :asc, :ASC, "asc", "ASC"
|
202
|
+
# 0
|
203
|
+
else
|
204
|
+
0
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def order_sql(something)
|
209
|
+
["ASC", "DESC"][order(something)]
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|