apotomo-datatable 0.0.1
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.
- data/MIT-LICENSE +20 -0
- data/README.md +113 -0
- data/Rakefile +46 -0
- data/lib/apotomo-datatable.rb +11 -0
- data/lib/apotomo-datatable/railtie.rb +24 -0
- data/lib/apotomo-datatable/version.rb +3 -0
- data/lib/apotomo/datatable/display_html.html.haml +25 -0
- data/lib/apotomo/datatable/display_js.html.haml +2 -0
- data/lib/apotomo/datatable/head_foot.html.haml +22 -0
- data/lib/apotomo/datatable_widget.rb +303 -0
- data/lib/tasks/apotomo-datatable_tasks.rake +4 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/features/load_datatable_in_various_ways_spec.rb +32 -0
- data/spec/features/load_datatable_in_various_ways_spec.rb.log +52 -0
- data/spec/features/server_side_processing_spec.rb +62 -0
- data/spec/features/server_side_processing_spec.rb.log +16 -0
- data/spec/widget/apotomo_datatable_widget_spec.rb +107 -0
- data/spec/widget/data_event_spec.rb +24 -0
- data/spec/widget/display_event_spec.rb +45 -0
- data/spec/widget/included_excluded_columns_spec.rb +38 -0
- data/spec/widget/merge_options_spec.rb +35 -0
- metadata +359 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 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.md
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
# Apotomo-Datatable
|
2
|
+
Rails Gem for generating jQuery Datatables with extremely minimal configuration
|
3
|
+
|
4
|
+
Built on the Apotomo widget gem
|
5
|
+
|
6
|
+
Pacaged with jQuery Datatables version 1.9.4
|
7
|
+
|
8
|
+
Datatables may be rendered within a view (like a partial) or as javascipt for AJAX implementation
|
9
|
+
|
10
|
+
## Usage
|
11
|
+
|
12
|
+
### Gemfile
|
13
|
+
gem 'apotomo-datatable'
|
14
|
+
gem 'haml'
|
15
|
+
|
16
|
+
### Simple use case for a given model/controller
|
17
|
+
|
18
|
+
#### items_controller.rb
|
19
|
+
has_widgets do |root|
|
20
|
+
root << datatable=widget('apotomo/datatable',:datatable)
|
21
|
+
end
|
22
|
+
|
23
|
+
#### Embedding with an HTML view
|
24
|
+
##### view/items/index.html.haml
|
25
|
+
=render_widget :datatable,:display
|
26
|
+
|
27
|
+
#### AJAX rendering
|
28
|
+
##### view/items/index.html.haml
|
29
|
+
%div#parentDiv
|
30
|
+
=link_to "Create table", items_path+'.js?template[parent]=parentDiv', :remote=>true, :title=>"Create table"
|
31
|
+
##### view/items/index.js.haml
|
32
|
+
=render_widget :datatable,:display
|
33
|
+
|
34
|
+
### Passing options from various points
|
35
|
+
|
36
|
+
#### items_controller.rb
|
37
|
+
root << datatable=widget('apotomo/datatable',:datatable,
|
38
|
+
:widget=>{}, #widget options (the model is derived from the controller name by default, but may be passed here as :model=>Model)
|
39
|
+
:template=>{:footer=>true}, #template options
|
40
|
+
:plugin=>{:sScrollY=>150} #plugin options, see: http://datatables.net/usage/options
|
41
|
+
)
|
42
|
+
|
43
|
+
def index
|
44
|
+
respond_to do |format|
|
45
|
+
format.html
|
46
|
+
format.js {render :script=>true}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# By defaultathe widget will query the model on its own
|
51
|
+
# If apotomo_datatable_datasource is defined, Apotomo::DatatableWidget.datasource will use this to populate
|
52
|
+
# The hash provided, which is expected to be standard search results from an ActiveRecord query, is encapsulated in a hash expected by jquery datatables
|
53
|
+
|
54
|
+
def apotomo_datatable_datasource(filter)
|
55
|
+
Item.find(:all,filter)
|
56
|
+
end
|
57
|
+
|
58
|
+
#### view/items/index.html.haml
|
59
|
+
%h1="Apotomo Datatable Example"
|
60
|
+
|
61
|
+
%h2="Rendered as HTML"
|
62
|
+
=render_widget :items_datatable,:display,:plugin=>{:sScrollY=>100,:bScrollCollapse=>true},:template=>{:id=>'html_datatable'}
|
63
|
+
|
64
|
+
%h2="Rendered via AJAX"
|
65
|
+
|
66
|
+
%div#parentDiv1
|
67
|
+
=link_to "Create table from options set in the URL", items_path+'.js?template[parent]=parentDiv1&plugin[sScrollY]=100', :remote=>true
|
68
|
+
|
69
|
+
:javascript
|
70
|
+
var plugin_options={sScrollY: 50, iDisplayStart: 20};
|
71
|
+
|
72
|
+
|
73
|
+
%div#parentDiv2
|
74
|
+
=link_to "Create table from options defined in javascript variable", items_path+'.js?template[plugin_options]=plugin_options&template[parent]=parentDiv2&template[id]=datatable_2', :remote=>true
|
75
|
+
|
76
|
+
#### index.js.haml
|
77
|
+
=render_widget :items_datatable,:display,:widget=>{},:template=>{:footer=>true},:plugin=>{:sScrollY=>150}
|
78
|
+
|
79
|
+
|
80
|
+
## Options
|
81
|
+
|
82
|
+
The @options hash includes sub-hashes for the widget, templates and client-side plugin
|
83
|
+
@options={:widget=>{...}, :template=>{...}, :plugin=>{...}}
|
84
|
+
|
85
|
+
Default options are generated and merged with controller-provided options in Apotomo::DatatableWidget.set_options
|
86
|
+
|
87
|
+
Default options may be overridden from the controller, view, by URL parameters and by a client-side javascript hash, as seen in the example above, with the client-side javascript hash taking the highest precedence
|
88
|
+
client_side_options -> url_param_options -> view_options -> controller_options -> default_options
|
89
|
+
|
90
|
+
URL parameters may only define template and plugin options. Defining widget options from the URL would present a security hole
|
91
|
+
|
92
|
+
The client-side hash may only define plugin options. Since this hash is not passed to the server template and widget options would never be seen
|
93
|
+
|
94
|
+
$.extend(@options[:widget].to_json,client_side_options) constitutes the arguments passed to the datatable initialization function.
|
95
|
+
See http://datatables.net/usage/options for options. As such, any option specified in the jquery datatables API may be set in this sub hash
|
96
|
+
Note: Server-side processing is not yet supported
|
97
|
+
|
98
|
+
By default, :id, :created_at and :updated_at columns are excluded from display.
|
99
|
+
Pass the [:template][:excluded_columns] option to exclude more
|
100
|
+
Pass the [:template][:included_columns] option to include excluded columns
|
101
|
+
|
102
|
+
## Current Status
|
103
|
+
|
104
|
+
The above examples will load a functional datatable, with sorting and global filtering working
|
105
|
+
Basic tests for loading and sorting are implemented. Sorting tests fail when plugin[bServerSide]=true since that is not implemented yet
|
106
|
+
Template for column-based filters started, but not yet complete or functional
|
107
|
+
|
108
|
+
## TODO
|
109
|
+
|
110
|
+
Implement server-side sorting and filtering
|
111
|
+
Expand feature tests
|
112
|
+
Implementing the other base features
|
113
|
+
Move on to implementing plugins
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
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 = 'ApotomoDatatable'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
Dir[File.join(File.dirname(__FILE__), 'tasks/**/*.rake')].each {|f| load f }
|
29
|
+
require 'rspec/core'
|
30
|
+
require 'rspec/core/rake_task'
|
31
|
+
desc "Run all specs in spec directory (excluding plugin specs)"
|
32
|
+
RSpec::Core::RakeTask.new(:spec => 'app:db:test:prepare')
|
33
|
+
task :default => :spec
|
34
|
+
|
35
|
+
=begin
|
36
|
+
|
37
|
+
Rake::TestTask.new(:test) do |t|
|
38
|
+
t.libs << 'test'
|
39
|
+
t.test_files = FileList['test/**/*_test.rb']
|
40
|
+
t.verbose = true
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
Bundler::GemHelper.install_tasks
|
46
|
+
=end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'apotomo/datatable_widget'
|
2
|
+
require 'apotomo-datatable/railtie'
|
3
|
+
module ApotomoDatatable
|
4
|
+
class Engine < Rails::Engine
|
5
|
+
# loads views from 'cell/views' and NOT from 'app/cells'
|
6
|
+
# config.paths.add 'app/cell_views', :with => 'cell/views'
|
7
|
+
|
8
|
+
# appends 'lib/my_cells_view_path' to this Railtie view path contribution
|
9
|
+
# config.paths['app/cell_views'] << 'lib/apotomo/datatable'
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "rails/railtie"
|
2
|
+
|
3
|
+
module ApotomoDatatable
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
# rake_tasks do
|
6
|
+
# load "apotomo/apotomo.rake"
|
7
|
+
# end
|
8
|
+
|
9
|
+
# As we are a Railtie only, the routes won't be loaded automatically. Beside that, we want our
|
10
|
+
# route to be the very first (otherwise #resources might supersede it).
|
11
|
+
# initializer 'apotomo.prepend_routes', :after => :add_routing_paths do |app|
|
12
|
+
# app.routes_reloader.paths.unshift(File.dirname(__FILE__) + "/../../config/routes.rb")
|
13
|
+
# end
|
14
|
+
|
15
|
+
# Include a lazy loader via has_widgets.
|
16
|
+
# initializer 'apotomo.add_has_widgets' do |app|
|
17
|
+
# ActionController::Base.extend Apotomo::Rails::ControllerMethodsLoader
|
18
|
+
# end
|
19
|
+
|
20
|
+
initializer 'apotomo-datatable.setup_view_paths', :after => 'apotomo.setup_view_paths' do |app|
|
21
|
+
Apotomo::DatatableWidget.setup_view_paths!
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
/default apotomo-datatable view
|
2
|
+
-if @merged_options[:widget][:model]
|
3
|
+
%table{:id=>@merged_options[:template][:id],:class=>"display dataTable"}<>
|
4
|
+
-if @merged_options[:template][:header]
|
5
|
+
%thead<>
|
6
|
+
=render({:state=>:head_foot},@merged_options,:header);
|
7
|
+
%tbody<>
|
8
|
+
-if !@merged_options[:plugin][:sAjaxSource] and !@merged_options[:plugin][:aaData]
|
9
|
+
-@merged_options[:widget][:datasource].call().each do |item|
|
10
|
+
%tr<>
|
11
|
+
-item.attributes.each do |key,value|
|
12
|
+
-if !@merged_options[:template][:excluded_columns].include?(key.to_sym) or @merged_options[:template][:included_columns].include?(key.to_sym)
|
13
|
+
%td<>=value
|
14
|
+
-if @merged_options[:template][:footer]
|
15
|
+
%tfoot<>
|
16
|
+
=render({:state=>:head_foot},@merged_options,:footer);
|
17
|
+
-if !@merged_options[:params][:format]
|
18
|
+
:javascript
|
19
|
+
postInit(function() {
|
20
|
+
#{@init_datatable_js}
|
21
|
+
});
|
22
|
+
-"#{@merged_options[:plugin].inspect}"
|
23
|
+
-else
|
24
|
+
="No Model Defined"
|
25
|
+
|
@@ -0,0 +1,22 @@
|
|
1
|
+
%tr<>
|
2
|
+
-merged_options[:widget][:model].columns_hash.each_pair do |name,column|
|
3
|
+
-if !@merged_options[:template][:excluded_columns].include?(name.to_sym) or @merged_options[:template][:included_columns].include?(name.to_sym)
|
4
|
+
%th<>
|
5
|
+
- if merged_options[:template][section].respond_to?(:each_pair)
|
6
|
+
- inputs=merged_options[:template][section][name]
|
7
|
+
- unless inputs
|
8
|
+
- inputs=merged_options[:template][section][:default]
|
9
|
+
- else
|
10
|
+
- inputs=merged_options[:template][section]
|
11
|
+
- unless inputs.respond_to?(:each)
|
12
|
+
- inputs=[inputs]
|
13
|
+
- inputs.each do |opt|
|
14
|
+
- case opt
|
15
|
+
- when :label
|
16
|
+
=name
|
17
|
+
- when :input
|
18
|
+
%br<>
|
19
|
+
%input{:onclick=>"event.stopPropagation();"}<>
|
20
|
+
- when :select
|
21
|
+
%br<>
|
22
|
+
%select{:onclick=>"event.stopPropagation();"}<>
|
@@ -0,0 +1,303 @@
|
|
1
|
+
require 'apotomo'
|
2
|
+
#include Rails.application.routes.url_helpers
|
3
|
+
|
4
|
+
=begin
|
5
|
+
Apotomo-Datatables
|
6
|
+
|
7
|
+
Basic usage with default options:
|
8
|
+
|
9
|
+
Gemfile
|
10
|
+
gem 'apotomo-datatables'
|
11
|
+
|
12
|
+
items_controller.rb
|
13
|
+
root << items_datatable=widget('apotomo/datatable',:items_datatable)
|
14
|
+
|
15
|
+
index.html.haml
|
16
|
+
#render as HTML like a partial
|
17
|
+
=render_widget :items_datatable,:display
|
18
|
+
|
19
|
+
#render via AJAX
|
20
|
+
%div#parentDiv
|
21
|
+
=link_to "Create table from options set in the URL", items_path+'.js?template[parent]=parentDiv, :remote=>true
|
22
|
+
|
23
|
+
index.js.haml #used to render via AJAX
|
24
|
+
=render_widget :items_datatable,:display
|
25
|
+
|
26
|
+
=end
|
27
|
+
|
28
|
+
class Apotomo::DatatableWidget < Apotomo::Widget
|
29
|
+
DEFAULT_VIEW_PATHS << File.expand_path('../../', __FILE__)
|
30
|
+
|
31
|
+
responds_to_event :data #Used by sAjaxSource plugin option
|
32
|
+
responds_to_event :display
|
33
|
+
responds_to_event :test_evt, :with => :test_evt, :passing => :root
|
34
|
+
|
35
|
+
after_initialize do
|
36
|
+
## set default options and those based on options provided in the has_widgets call in the controller
|
37
|
+
set_options(options)
|
38
|
+
@test_val=0
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_val
|
42
|
+
@test_val
|
43
|
+
end
|
44
|
+
|
45
|
+
def increment_test_val
|
46
|
+
@test_val=@test_val+1
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_evt(event)
|
50
|
+
if @merged_options[:widget][:controller].respond_to?(:apotomo_datatable_event)
|
51
|
+
@evt_test=@merged_options[:widget][:controller].apotomo_datatable_event(event)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def merged_options
|
56
|
+
@merged_options
|
57
|
+
end
|
58
|
+
|
59
|
+
def display(view_options={})
|
60
|
+
if view_options && view_options.respond_to?('each_pair')
|
61
|
+
## merge options provided by the render_widget method call in the view
|
62
|
+
@merged_options.deep_merge!(view_options)
|
63
|
+
end
|
64
|
+
|
65
|
+
## merge options from the URL params
|
66
|
+
merge_url_param_options(params)
|
67
|
+
process_boolean_options
|
68
|
+
|
69
|
+
##Build json string to pass plugin options to the client
|
70
|
+
##and command to merge with client-side plugin_options if provided
|
71
|
+
datatable_options=@merged_options[:plugin].to_json
|
72
|
+
if @merged_options[:template][:plugin_options]
|
73
|
+
datatable_options="$.extend(#{datatable_options},#{@merged_options[:template][:plugin_options]})"
|
74
|
+
end
|
75
|
+
|
76
|
+
#make sure :header and :footer are arrays
|
77
|
+
if @merged_options[:template][:header] && ! @merged_options[:template][:header].respond_to?('each') then @merged_options[:template][:header]=[@merged_options[:template][:header]] end
|
78
|
+
if @merged_options[:template][:footer] && ! @merged_options[:template][:footer].respond_to?('each') then @merged_options[:template][:footer]=[@merged_options[:template][:footer]] end
|
79
|
+
|
80
|
+
|
81
|
+
@init_datatable_js= "$(\"##{@merged_options[:template][:id]}\").dataTable(#{datatable_options});"
|
82
|
+
|
83
|
+
#this is just a test firing an event
|
84
|
+
@evt_test='empty'
|
85
|
+
self.fire :test_evt
|
86
|
+
if @merged_options[:params][:format]=='js'
|
87
|
+
#TODO: search the app's widget path for this template before using the default version
|
88
|
+
@html=render_to_string :file => File.expand_path('../../apotomo/datatable/display_html', __FILE__)
|
89
|
+
#escape double quotes and new lines, then make string safe so it's rendered properly
|
90
|
+
@html=@html.gsub(/[\n\r]/,' ').gsub(/"/,'\\\\"').html_safe
|
91
|
+
render :view=>:display_js
|
92
|
+
# render (replace :view=>:display_html, :selector=>'div#parent')+@init_datatable_js
|
93
|
+
else
|
94
|
+
render :view=>:display_html
|
95
|
+
# render :view=>File.expand_path('./datatable/display_html', __FILE__)
|
96
|
+
# render :view=>'app/widgets/apotomo/datatable/display_html'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# def view_for_state(state)
|
102
|
+
# "app/widgets/apotomo/datatable/#{state}"
|
103
|
+
# end
|
104
|
+
|
105
|
+
def datatable_init_vars
|
106
|
+
end
|
107
|
+
|
108
|
+
def head_foot(merged_options,section)
|
109
|
+
render :locals=>{:merged_options=>merged_options,:section=>section}
|
110
|
+
end
|
111
|
+
|
112
|
+
def data
|
113
|
+
is_searching = (params[:sSearch] and params[:sSearch].length>0)
|
114
|
+
@records=datasource
|
115
|
+
@data={
|
116
|
+
:iTotalRecords=>@merged_options[:widget][:model].count,
|
117
|
+
:iTotalDisplayRecords=>is_searching ? @records.count : @merged_options[:widget][:model].count,
|
118
|
+
:aaData=>@records
|
119
|
+
}
|
120
|
+
render text: @data.to_json
|
121
|
+
end
|
122
|
+
|
123
|
+
def datasource
|
124
|
+
#datatable passes something like
|
125
|
+
#"sEcho"=>"1", "iColumns"=>"5", "sColumns"=>"", "iDisplayStart"=>"0", "iDisplayLength"=>"10", "mDataProp_0"=>"id", "mDataProp_1"=>"text", "mDataProp_2"=>"created_at", "mDataProp_3"=>"updated_at", "mDataProp_4"=>"like", "sSearch"=>"", "bRegex"=>"false", "sSearch_0"=>"", "bRegex_0"=>"false", "bSearchable_0"=>"true", "sSearch_1"=>"", "bRegex_1"=>"false", "bSearchable_1"=>"true", "sSearch_2"=>"", "bRegex_2"=>"false", "bSearchable_2"=>"true", "sSearch_3"=>"", "bRegex_3"=>"false", "bSearchable_3"=>"true", "sSearch_4"=>"", "bRegex_4"=>"false", "bSearchable_4"=>"true", "iSortCol_0"=>"0", "sSortDir_0"=>"asc", "iSortingCols"=>"1", "bSortable_0"=>"true", "bSortable_1"=>"true", "bSortable_2"=>"true", "bSortable_3"=>"true", "bSortable_4"=>"true"
|
126
|
+
filter={}
|
127
|
+
is_searching = (params[:sSearch] and params[:sSearch].length>0)
|
128
|
+
if is_searching
|
129
|
+
filter[:conditions]=[@merged_options[:widget][:model].column_names.join(' LIKE :sSearch OR ')+' LIKE :sSearch',{:sSearch=>"%#{params[:sSearch]}%"}]
|
130
|
+
end
|
131
|
+
if params[:iDisplayStart] and params[:iDisplayLength]
|
132
|
+
filter[:limit]=params[:iDisplayLength]
|
133
|
+
filter[:offset]=params[:iDisplayStart]
|
134
|
+
end
|
135
|
+
if @merged_options[:widget][:controller].respond_to?('apotomo_datatable_datasource')
|
136
|
+
@records=@merged_options[:widget][:controller].apotomo_datatable_datasource(filter)
|
137
|
+
else
|
138
|
+
@records=@merged_options[:widget][:model].find(:all,filter)
|
139
|
+
end
|
140
|
+
return @records
|
141
|
+
end
|
142
|
+
|
143
|
+
def create
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
def edit
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
def update
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
def destroy
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
def set_options(controller_options)
|
160
|
+
=begin
|
161
|
+
Options:
|
162
|
+
|
163
|
+
The @merged_options hash includes primary keys for the widget, templates and client-side plugin
|
164
|
+
@merged_options={:widget=>{...}, :template=>{...}, :plugin=>{...}}
|
165
|
+
|
166
|
+
Default options are generated in Apotomo::DatatableWidget.set_options
|
167
|
+
|
168
|
+
Default options may be overridden from the controller, view, by URL parameters and by a client-side javascript hash, as seen in the example above,
|
169
|
+
with the client-side javascript hash taking the highest precedence
|
170
|
+
client_side_options -> url_param_options -> view_options -> controller_options -> default_options
|
171
|
+
|
172
|
+
URL parameters may only define template and plugin options. Defining widget options from the URL would present a security hole
|
173
|
+
The client-side hash may only define plugin options. Since it is not passed to the server, template and widget options would be irrelevant
|
174
|
+
|
175
|
+
$.extend(@merged_options[:widget].to_json,client_side_options) constitutes the arguments passed to the datatable initialization function.
|
176
|
+
See http://datatables.net/usage/options for options. As such, any option specified in the jquery datatables API may be set in this sub hash
|
177
|
+
|
178
|
+
|
179
|
+
=end
|
180
|
+
#initialize @merged_options, which will contain the final merged hash of options
|
181
|
+
@merged_options={:widget=>{},:template=>{},:plugin=>{}}.with_indifferent_access
|
182
|
+
|
183
|
+
#make sure options (passed by controller in has_widgets) has the basic hash structure
|
184
|
+
controller_options=controller_options.respond_to?(:each_pair) ? controller_options : {}.with_indifferent_access
|
185
|
+
controller_options=@merged_options.deep_merge(controller_options)
|
186
|
+
controller=parent_controller
|
187
|
+
if match=/(\w+?)sController/.match(controller.class.name.to_s)
|
188
|
+
controller_model_name=match[1]
|
189
|
+
end
|
190
|
+
|
191
|
+
#get model first since it is used to build other default options
|
192
|
+
model=nil
|
193
|
+
if controller_options[:widget].has_key?(:model)
|
194
|
+
if controller_options[:widget][:model].respond_to?("columns_hash")
|
195
|
+
model=controller_options[:widget][:model]
|
196
|
+
end
|
197
|
+
elsif controller_model_name
|
198
|
+
#derive the model from the controller name
|
199
|
+
if defined?(controller_model_name) && eval(controller_model_name+'.respond_to?("columns_hash")')
|
200
|
+
model=eval(controller_model_name)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
if model==nil then
|
204
|
+
raise "Cannot use apotomo-datatable without a model. Either pass a model in the has_widgets method call or make sure a model exists with a name corresponding to the controller from which has_widgets is called"
|
205
|
+
end
|
206
|
+
|
207
|
+
default_options={
|
208
|
+
:widget=>{
|
209
|
+
:name=>"#{model.name}DatatableWidget",
|
210
|
+
:model=>model,
|
211
|
+
:controller=>controller,
|
212
|
+
:datasource=>self.method(:datasource),
|
213
|
+
:test_option=>'default'
|
214
|
+
},
|
215
|
+
:template=>{
|
216
|
+
#The header and footer have the same set of options.
|
217
|
+
#Each may contain multiple rows. Each row may define an array of options for each cell
|
218
|
+
#:header=
|
219
|
+
|
220
|
+
#Each may be a single value, an array or a hash
|
221
|
+
#If a single value or array, all columns are rendered with the provided options in order
|
222
|
+
#If a hash, each key should match column field names. Each key-value is a value or array as above
|
223
|
+
#single value or array options are: nil: ommited, label: label, input: input column filter, select: select column filter
|
224
|
+
# :header=>{:default=>:label,:name=>[:label,:input],:value=>[:label,:input]},
|
225
|
+
:header=>{:default=>:label},
|
226
|
+
:footer=>nil,
|
227
|
+
:id=>"#{model.name}Datatable",
|
228
|
+
:excluded_columns=>[:id,:created_at,:updated_at], #set to a list of field names to exclude from display
|
229
|
+
:included_columns=>[], #set to a list of columns to include even if they are excluded in :excluded_columns
|
230
|
+
:test_option=>'default'
|
231
|
+
},
|
232
|
+
:plugin=>{
|
233
|
+
:iDisplayStart=>0,
|
234
|
+
:bProcessing=>true,
|
235
|
+
:bJQueryUI=>true,
|
236
|
+
:test_option=>'default'
|
237
|
+
}
|
238
|
+
}.with_indifferent_access
|
239
|
+
default_options[:plugin][:aoColumns]=[]
|
240
|
+
model.column_names.each do |name|
|
241
|
+
default_options[:plugin][:aoColumns].push({'mDataProp'=>name})
|
242
|
+
end
|
243
|
+
|
244
|
+
# merge default options with options provided by the controller
|
245
|
+
@merged_options=default_options.deep_merge(controller_options)
|
246
|
+
@merged_options[:params]=params
|
247
|
+
end
|
248
|
+
|
249
|
+
def merge_url_param_options(url_param_options)
|
250
|
+
#:widget options are not accepted from URL parameters - accepting them would be a security hole
|
251
|
+
if url_param_options.has_key?(:template) && url_param_options[:template].respond_to?('each_pair')
|
252
|
+
@merged_options[:template].deep_merge!(url_param_options[:template])
|
253
|
+
end
|
254
|
+
if url_param_options.has_key?(:plugin) && url_param_options[:plugin].respond_to?('each_pair')
|
255
|
+
@merged_options[:plugin].deep_merge!(url_param_options[:plugin])
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
def process_boolean_options
|
260
|
+
#some options accept boolean options to indicate the default value (true) or undefined (false or nil)
|
261
|
+
#these must be processed after options from all sources have been merged
|
262
|
+
#Some true values are converted to default parameters for the plugin
|
263
|
+
#Some false values are deleted from the hash to allow the plugin to apply its own default options
|
264
|
+
|
265
|
+
## if options[:plugin][:sAjaxSource] is boolean or nil, derive default if true and delete option value from controller
|
266
|
+
if @merged_options[:plugin].has_key?(:sAjaxSource)
|
267
|
+
sAjaxSource_bool=make_bool(@merged_options[:plugin][:sAjaxSource])
|
268
|
+
if sAjaxSource_bool
|
269
|
+
@merged_options[:plugin][:sAjaxSource]=url_for_event(:data)
|
270
|
+
unless @merged_options[:plugin].has_key?(:bServerSide)
|
271
|
+
@merged_options[:plugin][:bServerSide]=true # User server-side processing: http://datatables.net/ref#bServerSide
|
272
|
+
end
|
273
|
+
else
|
274
|
+
@merged_options[:plugin].delete(:sAjaxSource) #delete false or nil value to prevent invalid option from passing to plugin
|
275
|
+
end
|
276
|
+
end
|
277
|
+
## profide column mapping if using ajax or aaData
|
278
|
+
## provide aaData if requested
|
279
|
+
if sAjaxSource_bool || @merged_options[:plugin][:aaData]==true
|
280
|
+
if @merged_options[:plugin][:aaData]==true
|
281
|
+
records=datasource
|
282
|
+
@merged_options[:plugin][:aaData]=records
|
283
|
+
end
|
284
|
+
else
|
285
|
+
@merged_options[:plugin].delete(:aoColumns)
|
286
|
+
end
|
287
|
+
@merged_options[:plugin][:sAjaxSourceBOOL]=sAjaxSource_bool
|
288
|
+
end
|
289
|
+
|
290
|
+
def make_bool(val)
|
291
|
+
if !!val==val
|
292
|
+
return val
|
293
|
+
else
|
294
|
+
if val.is_a?(String) && val.downcase=="true"
|
295
|
+
return true
|
296
|
+
else
|
297
|
+
return false
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
|