usefull_table 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +12 -0
- data/Gemfile +27 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +234 -0
- data/Rakefile +31 -0
- data/app/controllers/usefull_table/table_controller.rb +34 -0
- data/app/helpers/usefull_table_helper.rb +323 -0
- data/app/views/usefull_table/table/create.xlsx.maker +17 -0
- data/config/routes.rb +8 -0
- data/lib/generators/usefull_table/install/install_generator.rb +47 -0
- data/lib/generators/usefull_table/install/templates/config/locales/usefull_table.it.yml +42 -0
- data/lib/generators/usefull_table/install/templates/public/images/usefull_table_destroy.png +0 -0
- data/lib/generators/usefull_table/install/templates/public/images/usefull_table_download.png +0 -0
- data/lib/generators/usefull_table/install/templates/public/images/usefull_table_edit.png +0 -0
- data/lib/generators/usefull_table/install/templates/public/images/usefull_table_false.png +0 -0
- data/lib/generators/usefull_table/install/templates/public/images/usefull_table_show.png +0 -0
- data/lib/generators/usefull_table/install/templates/public/images/usefull_table_true.png +0 -0
- data/lib/generators/usefull_table/install/templates/public/stylesheets/usefull_table.css +101 -0
- data/lib/generators/usefull_table/scaffold/scaffold_generator.rb +12 -0
- data/lib/generators/usefull_table/scaffold/templates/lib/templates/erb/scaffold/index.html.erb +15 -0
- data/lib/generators/usefull_table/scaffold/templates/lib/templates/erb/scaffold/show.html.erb +12 -0
- data/lib/generators/usefull_table/scaffold/templates/lib/templates/rails/scaffold_controller/controller.rb +84 -0
- data/lib/usefull_table/engine.rb +17 -0
- data/lib/usefull_table/exceptions.rb +17 -0
- data/lib/usefull_table/table_builder.rb +522 -0
- data/lib/usefull_table/version.rb +3 -0
- data/lib/usefull_table.rb +13 -0
- metadata +123 -0
data/CHANGELOG.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
ToDo
|
2
|
+
- Autodetection in table data of: boolean and 'true' and 'false'. To render with red and green traffic-light image.
|
3
|
+
- Add tip to cell
|
4
|
+
- Add option :excel => false to column to remove from excel export
|
5
|
+
- Add option [:export][:type] => :xls, :xlsx, :pdf, :all, [:xls, :xlsx]
|
6
|
+
|
7
|
+
BugToFix
|
8
|
+
1.0.1 (June 29, 2012)
|
9
|
+
- First working release
|
10
|
+
|
11
|
+
0.1.0 (June 18, 2012)
|
12
|
+
- first Release
|
data/Gemfile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
#remove in production
|
4
|
+
#gem "acts_as_xls", :path => "/home/apps/rails_apps/gems/acts_as_xls"
|
5
|
+
#gem "acts_as_monitor", :path => "/home/apps/rails_apps/gems/acts_as_monitor"
|
6
|
+
gem "rails", "3.0.9"
|
7
|
+
#gem "in_place_editing"
|
8
|
+
|
9
|
+
group :development do
|
10
|
+
gem "acts_as_monitor", :path => "/home/apps/rails_apps/gems/acts_as_monitor"
|
11
|
+
gem "acts_as_xls", :path => "/home/apps/rails_apps/gems/acts_as_xls"
|
12
|
+
gem "meta_search"
|
13
|
+
gem "will_paginate"
|
14
|
+
gem "ruby-debug"
|
15
|
+
end
|
16
|
+
|
17
|
+
group :test do
|
18
|
+
gem "acts_as_monitor", :path => "/home/apps/rails_apps/gems/acts_as_monitor"
|
19
|
+
gem "acts_as_xls", :path => "/home/apps/rails_apps/gems/acts_as_xls"
|
20
|
+
gem "capybara", ">= 0.4.0"
|
21
|
+
gem "meta_search"
|
22
|
+
gem "will_paginate"
|
23
|
+
gem "ruby-debug"
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
gemspec
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 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,234 @@
|
|
1
|
+
=UsefullTable
|
2
|
+
table_for generate a full-optionals table, with excel export, columns ordering, links, inline edit and monitoring (ActsAsMonitor https://github.com/skylord73/acts_as_monitor)
|
3
|
+
but don't warry because a rich set of defaults, make its use very simple
|
4
|
+
|
5
|
+
for a working sample please refer to test/dummy
|
6
|
+
|
7
|
+
==Setup
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
gem 'usefull_table'
|
10
|
+
|
11
|
+
then execute
|
12
|
+
$ bundle install
|
13
|
+
|
14
|
+
or install it yourself as:
|
15
|
+
$ sudo gem install usefull_table
|
16
|
+
|
17
|
+
copy icons, javascript and stylesheets:
|
18
|
+
$ rails g usefull_table:install
|
19
|
+
|
20
|
+
modify default scaffold to use usefull_table, meta_search and will_paginate (controller and index.html.erb):
|
21
|
+
$ rails g usefull_table:scaffold
|
22
|
+
|
23
|
+
|
24
|
+
==Usage
|
25
|
+
Write few lines in your controller
|
26
|
+
app/controllers/home_controller.rb
|
27
|
+
def index
|
28
|
+
@search = Item.search(params[:search])
|
29
|
+
...
|
30
|
+
respond_to do |format|
|
31
|
+
format.html { @items = @search.paginate(:page => params[:page]) }
|
32
|
+
end
|
33
|
+
...
|
34
|
+
end
|
35
|
+
|
36
|
+
and in your view
|
37
|
+
app/views/home/my_view.html.erb
|
38
|
+
<%= table_for @items, @search, options = {} do |t| %>
|
39
|
+
<% t.show :url => Proc.new { |item| item_path(item)} %>
|
40
|
+
<% t.edit :url => Proc.new { |item| edit_item_path(item)}%>
|
41
|
+
<% t.destroy :url => Proc.new { |item| item_path(item)}, :link_options => {:method => delete, :confirm => "are you sure?"} %>
|
42
|
+
<% t.download :url => Proc.new { |item| download_item_path(item)} %>
|
43
|
+
<% t.col :name %>
|
44
|
+
<% t.col "user.name" %>
|
45
|
+
<% t.status %>
|
46
|
+
<% end %>
|
47
|
+
|
48
|
+
==Options
|
49
|
+
default values in *bold*
|
50
|
+
|
51
|
+
===Paginator
|
52
|
+
options[:paginator][:visible] = *true* | false _note_: false if @items not present
|
53
|
+
options[:paginator][:class] = *"usefull_table_paginator"*
|
54
|
+
|
55
|
+
===Container
|
56
|
+
options[:html] = *{:class => "usefull_table_container"}*
|
57
|
+
|
58
|
+
===Excel
|
59
|
+
options[:export][:visible] = *true* | false
|
60
|
+
options[:export][:filter] = *true* | false _note:_ false if @search not present
|
61
|
+
options[:export][:human] = *true* | false
|
62
|
+
options[:export][:worksheet] = *object.class.name.gsub(/::/,"#")* _note:_ class name with namespace separator #
|
63
|
+
options[:export][:url] = Custom Url and format
|
64
|
+
|
65
|
+
===Table
|
66
|
+
options[:table][:div_html] = *{:class => "usefull_table"}*
|
67
|
+
options[:table][:header_html] = *{:class => "first_row"}*
|
68
|
+
options[:table][:header_type] = *:sort* _note:_ :human if @search not present (no sorting possible)
|
69
|
+
:plain bare column name from ActiveRecord
|
70
|
+
:human column name humanized by ActiveRecord
|
71
|
+
:nil no column name
|
72
|
+
|
73
|
+
==Localization
|
74
|
+
Uses standard ActiveRecord localization to render tables and columns names
|
75
|
+
it:
|
76
|
+
activerecord:
|
77
|
+
attributes:
|
78
|
+
item:
|
79
|
+
name: Name
|
80
|
+
type: Type
|
81
|
+
user:
|
82
|
+
name: Name
|
83
|
+
models:
|
84
|
+
item:
|
85
|
+
one: Item
|
86
|
+
other: Items
|
87
|
+
user:
|
88
|
+
one: User
|
89
|
+
other: Users
|
90
|
+
|
91
|
+
#config/usefull_table.it.yml
|
92
|
+
it:
|
93
|
+
usefull_table:
|
94
|
+
submit_excel: Excel
|
95
|
+
header_error: Errore
|
96
|
+
body_error: Errore
|
97
|
+
|
98
|
+
icons:
|
99
|
+
show: "usefull_table_show.png"
|
100
|
+
edit: "usefull_table_edit.png"
|
101
|
+
destroy: "usefull_table_destroy.png"
|
102
|
+
download: "usefull_table_download.png"
|
103
|
+
|
104
|
+
=Column Types
|
105
|
+
==col
|
106
|
+
Render column value
|
107
|
+
|
108
|
+
===Usage
|
109
|
+
<% t.col :name %> #render column :name ( t.col "name" is ok)
|
110
|
+
<% t.col "user.name" %> #render column name of the user collection in item (item.user.name)
|
111
|
+
|
112
|
+
===Options
|
113
|
+
|
114
|
+
:header_type =>
|
115
|
+
- *:sort* #Header is MetaSearch#sort_link of columns_name
|
116
|
+
- :human #Header is plain text humanized with ActiveRecord column name
|
117
|
+
- :nil #No header
|
118
|
+
|
119
|
+
:label =>
|
120
|
+
- "Custom Name" #plain text without localization
|
121
|
+
- :custom_name #localized text in lazy context (.)
|
122
|
+
|
123
|
+
:data_type => #default get class name from object to render
|
124
|
+
- :Date
|
125
|
+
- :Time
|
126
|
+
- :DateTime
|
127
|
+
- :Currency
|
128
|
+
- :Bool #Transform value in boolean
|
129
|
+
- :Bool_reverse #Transform vale in boolean and reverse the vale
|
130
|
+
|
131
|
+
:url =>
|
132
|
+
- "static_path"
|
133
|
+
- Proc #Proc expose the object instance of the current row
|
134
|
+
|
135
|
+
:inline =>
|
136
|
+
- *false*
|
137
|
+
- true #enable inline editing for the column, works also with nested fields (no controller add-on required)
|
138
|
+
|
139
|
+
==label
|
140
|
+
Render static label
|
141
|
+
|
142
|
+
===Usage
|
143
|
+
<% t.label object %> #render object.inspect
|
144
|
+
<% t.label Proc.new {|item| item.name.capitalize} %> #Evaluate proc with item instance of the corresponding row
|
145
|
+
|
146
|
+
==monitor
|
147
|
+
Render a tri-state icon to monitor model status
|
148
|
+
* Red : Error
|
149
|
+
* Yellow: Warning
|
150
|
+
* Green: Status ok
|
151
|
+
|
152
|
+
Enable only if acts_as_monitor gem is required (https://github.com/skylord73/acts_as_monitor)
|
153
|
+
|
154
|
+
==Usage
|
155
|
+
<% t.monitor %>
|
156
|
+
|
157
|
+
Clicking the icon you get the comlete problem description pushed by Ajaxs script (no page reload)
|
158
|
+
|
159
|
+
==link
|
160
|
+
Create a link to something, using Icons or CustomText
|
161
|
+
|
162
|
+
===Usage
|
163
|
+
<% t.show :url => Proc.new {|object| home_path(object) }"%>
|
164
|
+
<% t.destroy :url => Proc.new {|object| home_path(object) }"%>
|
165
|
+
<% t.link :name => "Custom Link", :url => Proc.new {|object| my_link_home_path(object) }"%> #text link (Custom Link) to url
|
166
|
+
<% t.link :name => "Custom Link", :body_typ => :icon, :url => Proc.new {|object| my_link_home_path(object) }"%> #icon link with icon name = usefull_table_cusom_link.png or localization in usefull_table.icons.custom_link
|
167
|
+
|
168
|
+
===Options
|
169
|
+
|
170
|
+
:url =>
|
171
|
+
- Proc
|
172
|
+
- "my_custom_static_url"
|
173
|
+
|
174
|
+
:label =>
|
175
|
+
- :show_doc #localized in lazy contest (.)
|
176
|
+
- "Show Doc" #printed without localization
|
177
|
+
|
178
|
+
:link_options =>
|
179
|
+
- *nil*
|
180
|
+
- {:method => delete, :confirm => "sicuro?"} if name == :destroy
|
181
|
+
|
182
|
+
:name =>
|
183
|
+
- :symbol
|
184
|
+
- "string" #if method_name == :link the name is used as link_text (localized if symbol), ignored elsewhere
|
185
|
+
|
186
|
+
==bool
|
187
|
+
Create a boolean value using images to represent status.
|
188
|
+
Images name can be changed in locales
|
189
|
+
|
190
|
+
===Usage
|
191
|
+
<% t.bool :name %>
|
192
|
+
<% t.bool :name, :reverse => true%>
|
193
|
+
|
194
|
+
===Options
|
195
|
+
:header_type =>
|
196
|
+
- *:sort* #Header is MetaSearch#sort_link of columns_name
|
197
|
+
- :human #Header is plain text humanized with ActiveRecord column name
|
198
|
+
- :nil #No header
|
199
|
+
|
200
|
+
:label =>
|
201
|
+
- "Custom Name" #plain text without localization in header
|
202
|
+
- :custom_name #localized text in lazy context (.) in header
|
203
|
+
|
204
|
+
:url =>
|
205
|
+
- "my_custom_static_url"
|
206
|
+
- Proc #Proc expose the object instance of the current row
|
207
|
+
|
208
|
+
:reverse =>
|
209
|
+
- *false*
|
210
|
+
- true #reverse boolean value
|
211
|
+
|
212
|
+
==Personalization
|
213
|
+
|
214
|
+
Feel free to modify the following files:
|
215
|
+
|
216
|
+
- public/stylesheets/usefull_table.css
|
217
|
+
- config/locales/usefull_table.it.yml
|
218
|
+
|
219
|
+
==Contributing
|
220
|
+
|
221
|
+
1. Fork it
|
222
|
+
2. Create your feature branch (git checkout -b my-new-feature)
|
223
|
+
3. Commit your changes (git commit -am 'Added some feature')
|
224
|
+
4. Push to the branch (git push origin my-new-feature)
|
225
|
+
5. Create new Pull Request
|
226
|
+
|
227
|
+
==Thanks
|
228
|
+
|
229
|
+
Many thanks to :
|
230
|
+
- MetaSearch
|
231
|
+
- WillPaginate
|
232
|
+
- Spreadsheet
|
233
|
+
- Axlsx
|
234
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require 'rubygems'
|
3
|
+
begin
|
4
|
+
require 'bundler/setup'
|
5
|
+
require "bundler/gem_tasks"
|
6
|
+
rescue LoadError
|
7
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'rake'
|
11
|
+
require 'rake/testtask'
|
12
|
+
require 'rdoc/task'
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
Rake::TestTask.new(:test) do |t|
|
17
|
+
t.libs << 'lib'
|
18
|
+
t.libs << 'test'
|
19
|
+
t.pattern = 'test/**/*_test.rb'
|
20
|
+
t.verbose = false
|
21
|
+
end
|
22
|
+
|
23
|
+
task :default => :test
|
24
|
+
|
25
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
26
|
+
rdoc.rdoc_dir = 'rdoc'
|
27
|
+
rdoc.title = 'UsefullTable'
|
28
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
29
|
+
rdoc.rdoc_files.include('README.rdoc')
|
30
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
31
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module UsefullTable
|
2
|
+
class TableController < ::ApplicationController
|
3
|
+
|
4
|
+
def create
|
5
|
+
usefull_table = HashWithIndifferentAccess.new(ActiveSupport::JSON.decode(params[:usefull_table]))
|
6
|
+
#Rails::logger.info("MonitorsController back=#{usefull_table[:paths].inspect}")
|
7
|
+
if usefull_table[:class_name].present?
|
8
|
+
if usefull_table[:search].present?
|
9
|
+
@object = usefull_table[:class_name].constantize.search(usefull_table[:search]).relation
|
10
|
+
else
|
11
|
+
@object = usefull_table[:class_name].constantize.all
|
12
|
+
end
|
13
|
+
@params = usefull_table[:params]
|
14
|
+
end
|
15
|
+
|
16
|
+
respond_to do |format|
|
17
|
+
format.html
|
18
|
+
format.xlsx { render :xlsx => "create", :template => select_path(usefull_table[:paths],"xlsx.maker") }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def update
|
23
|
+
#usefull_table = HashWithIndifferentAccess.new(ActiveSupport::JSON.decode(params[:usefull_table]))
|
24
|
+
Rails::logger.info("TableController#update params=#{params.inspect}")
|
25
|
+
if params[:class_name].present? && params[:attribute_name].present?
|
26
|
+
@item = params[:class_name].to_s.camelize.constantize.find(params[:id])
|
27
|
+
@item.update_attribute(params[:attribute_name], params[:value])
|
28
|
+
render :text => CGI::escapeHTML(@item.send(params[:attribute_name]).to_s)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,323 @@
|
|
1
|
+
module UsefullTableHelper
|
2
|
+
#=UsefullTable
|
3
|
+
#table_for generate a full-optionals table, with excel export, columns ordering, links, inline edit and monitoring (ActsAsMonitor gem)
|
4
|
+
#but don't warry because of a rich set of defaults, make its use very simple
|
5
|
+
#
|
6
|
+
#==Setup
|
7
|
+
#Add this line to your application's Gemfile:
|
8
|
+
# gem 'usefull_table'
|
9
|
+
#
|
10
|
+
#then execute
|
11
|
+
# $ bundle install
|
12
|
+
#
|
13
|
+
#or install it yourself as:
|
14
|
+
# $ sudo gem install usefull_table
|
15
|
+
#
|
16
|
+
#copy icons, javascript and stylesheets:
|
17
|
+
# $ rails g usefull_table:install
|
18
|
+
#
|
19
|
+
#==Usage table_for
|
20
|
+
#Write few lines in your controller
|
21
|
+
# app/controllers/home_controller.rb
|
22
|
+
# def index
|
23
|
+
# @search = Item.search(params[:search])
|
24
|
+
# ...
|
25
|
+
# respond_to do |format|
|
26
|
+
# format.html { @items = @search.paginate(:page => params[:page]) }
|
27
|
+
# end
|
28
|
+
# ...
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
#and in your view
|
32
|
+
# app/views/home/my_view.html.erb
|
33
|
+
# <%= table_for @items, @search, options = {} do |t| %>
|
34
|
+
# <% t.show :url => Proc.new { |item| item_path(item)} %>
|
35
|
+
# <% t.edit :url => Proc.new { |item| edit_item_path(item)}%>
|
36
|
+
# <% t.destroy :url => Proc.new { |item| item_path(item)}, :link_options => {:method => delete, :confirm => "are you sure?"} %>
|
37
|
+
# <% t.download :url => Proc.new { |item| download_item_path(item)} %>
|
38
|
+
# <% t.col :name %>
|
39
|
+
# <% t.col "user.name" %>
|
40
|
+
# <% t.status %>
|
41
|
+
# <% end %>
|
42
|
+
#
|
43
|
+
#==Options
|
44
|
+
#default values in *bold*
|
45
|
+
#
|
46
|
+
#===Paginator
|
47
|
+
# options[:paginator][:visible] = *true* | false _note_: false if @items not present
|
48
|
+
# options[:paginator][:class] = *"usefull_table_paginator"*
|
49
|
+
#
|
50
|
+
#===Container
|
51
|
+
# options[:html] = *{:class => "usefull_table_container"}*
|
52
|
+
#
|
53
|
+
#===Excel
|
54
|
+
# options[:export][:visible] = *true* | false
|
55
|
+
# options[:export][:filter] = *true* | false _note:_ false if @search not present
|
56
|
+
# options[:export][:human] = *true* | false
|
57
|
+
# options[:export][:worksheet] = *object.class.name.gsub(/::/,"#")* _note:_ class name with namespace separator #
|
58
|
+
# options[:export][:url] = custom url
|
59
|
+
#===Table
|
60
|
+
# options[:table][:div_html] = *{:class => "usefull_table"}*
|
61
|
+
# options[:table][:header_html] = *{:class => "first_row"}*
|
62
|
+
# options[:table][:header_type] = *:sort* _note:_ :human if @search not present (no sorting possible)
|
63
|
+
# :plain bare column name from ActiveRecord
|
64
|
+
# :human column name humanized by ActiveRecord
|
65
|
+
# :nil no column name
|
66
|
+
#
|
67
|
+
#==Localization
|
68
|
+
#Uses standard ActiveRecord localization to render tables and columns names
|
69
|
+
# it:
|
70
|
+
# activerecord:
|
71
|
+
# attributes:
|
72
|
+
# item:
|
73
|
+
# name: Name
|
74
|
+
# type: Type
|
75
|
+
# user:
|
76
|
+
# name: Name
|
77
|
+
# models:
|
78
|
+
# item:
|
79
|
+
# one: Item
|
80
|
+
# other: Items
|
81
|
+
# user:
|
82
|
+
# one: User
|
83
|
+
# other: Users
|
84
|
+
#
|
85
|
+
# #config/usefull_table.it.yml
|
86
|
+
# it:
|
87
|
+
# usefull_table:
|
88
|
+
# submit_excel: Excel
|
89
|
+
# header_error: Errore
|
90
|
+
# body_error: Errore
|
91
|
+
#
|
92
|
+
# icons:
|
93
|
+
# show: "usefull_table_show.png"
|
94
|
+
# edit: "usefull_table_edit.png"
|
95
|
+
# destroy: "usefull_table_destroy.png"
|
96
|
+
# download: "usefull_table_download.png"
|
97
|
+
#
|
98
|
+
def table_for(obj, *args, &block)
|
99
|
+
#Rails::logger.info("table_for START args=#{args.inspect}")
|
100
|
+
unless obj.blank?
|
101
|
+
search = args.shift if args[0].kind_of?(MetaSearch::Builder)
|
102
|
+
#Rails::logger.info("table_for START(1) search=#{search.inspect}")
|
103
|
+
options = args.extract_options!
|
104
|
+
raise UsefullTable::MissingBlock unless block_given?
|
105
|
+
|
106
|
+
if obj.kind_of?(MetaSearch::Builder)
|
107
|
+
search = obj
|
108
|
+
object = obj.relation
|
109
|
+
search_attributes = search.search_attributes
|
110
|
+
else
|
111
|
+
object = obj
|
112
|
+
end
|
113
|
+
|
114
|
+
builder = UsefullTable::TableBuilder.new(object, search, options, self, &block)
|
115
|
+
options = builder.options
|
116
|
+
|
117
|
+
out = ""
|
118
|
+
out << monitor_tag_js if options[:monitor][:visible] == true
|
119
|
+
out << stylesheet_link_tag('usefull_table.css')
|
120
|
+
out << content_tag(:div, options[:html]) do
|
121
|
+
ext = ''
|
122
|
+
ext << usefull_table_paginator_for(object, options[:paginator])
|
123
|
+
ext << usefull_table_export_for(object,search,builder, options[:export])
|
124
|
+
ext << usefull_table_for(builder, object, search, options[:table])
|
125
|
+
ext << usefull_table_paginator_for(object, options[:paginator])
|
126
|
+
ext.html_safe
|
127
|
+
end
|
128
|
+
out.html_safe
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
#Instantiate builder with data info and render arrays for every line
|
133
|
+
#
|
134
|
+
#==Usage
|
135
|
+
#If you can use params to clone an existing table (builder.to_param) and return an array of Arrays
|
136
|
+
# $ array = export_for(@object, @params)
|
137
|
+
#
|
138
|
+
#You can build a new table passing a block (see ::table_for
|
139
|
+
def export_for(object, params = nil, &block)
|
140
|
+
builder = UsefullTable::TableBuilder.new(object, nil, nil, self, :params => params, &block)
|
141
|
+
builder.to_a
|
142
|
+
end
|
143
|
+
|
144
|
+
#Draw inline edit field
|
145
|
+
def inline_field(object, id, method, value, id_relation, tag_options = {}, in_place_editor_options = {})
|
146
|
+
Rails::logger.info("table_for#inline_field : oject=#{object.inspect}, method=#{method.inspect}, id=#{id.inspect}")
|
147
|
+
tag_options = { :tag => "span",
|
148
|
+
:id => "#{object.name.underscore.gsub("/","_")}_#{method}_#{id}_#{id_relation}_in_place_editor",
|
149
|
+
:class => "in_place_editor_field"}
|
150
|
+
id_relation = id if id_relation.nil?
|
151
|
+
in_place_editor_options[:url] = url_for({:action => "update", :controller=>"usefull_table/table", :id => id_relation})
|
152
|
+
in_place_editor_options[:parameters] = { :class_name => object.name.underscore, :attribute_name => method}
|
153
|
+
tag = content_tag(tag_options.delete(:tag), h(value),tag_options)
|
154
|
+
return tag + in_place_editor(tag_options[:id], in_place_editor_options)
|
155
|
+
end
|
156
|
+
|
157
|
+
private
|
158
|
+
|
159
|
+
#==Paginator
|
160
|
+
#Add pagination to Table
|
161
|
+
#===Parameters
|
162
|
+
# :paginator => {
|
163
|
+
# :visible => true | false #Default: true
|
164
|
+
# :class => ""usefull_table_paginator"
|
165
|
+
#}
|
166
|
+
def usefull_table_paginator_for(object, options = {})
|
167
|
+
if options[:visible] == true
|
168
|
+
#Rails::logger.info("table_for#paginator_tag : enter object=#{object.inspect}, options=#{options.inspect}")
|
169
|
+
content_tag :div, :class => options[:class] do
|
170
|
+
content_tag(:div, page_entries_info(object), :class => 'page_info') +
|
171
|
+
will_paginate(object, :container => false)
|
172
|
+
end
|
173
|
+
else
|
174
|
+
""
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#==Export
|
179
|
+
#Export table content to excel file
|
180
|
+
#
|
181
|
+
#Send to controller the following parameters to rebuild the table in excel format
|
182
|
+
#* Search filters
|
183
|
+
#* Columns (@data)
|
184
|
+
#* Values (evenif calculated locally)
|
185
|
+
#===Parameters
|
186
|
+
# :excel => {
|
187
|
+
# :visible => true | false #default: true
|
188
|
+
# :columns => :all #Export all model columns, if not present exports only table columns
|
189
|
+
# :url => "documents_path" #Url to controller returning xls file
|
190
|
+
# :human => true | false #default: true , Humanize column names
|
191
|
+
# :filter => true | false #default: true, export filtered data
|
192
|
+
#
|
193
|
+
def usefull_table_export_for(object,search,builder,options)
|
194
|
+
if options[:visible] == true
|
195
|
+
if options[:search] == true
|
196
|
+
@params = {}
|
197
|
+
@params[:search] = search.search_attributes unless search.blank?
|
198
|
+
@params[:class_name] = object.first.class.name
|
199
|
+
@params[:params] = builder.to_param
|
200
|
+
@params[:paths] = view_paths.map {|path| "#{path.to_path}/#{controller_name}/#{action_name}.xlsx.maker"}
|
201
|
+
#Rails::logger.info("table_for#excel_tag @path=#{self.controller_name}, action=#{action_name}, path=#{view_paths.first.to_path}\n\n")
|
202
|
+
content_tag(:div, :class => options[:class]) do
|
203
|
+
form_tag( options[:url] , :method => :post) do
|
204
|
+
hidden_field_tag("usefull_table", @params.to_json) +
|
205
|
+
submit_tag(I18n.t(:submit_excel, :scope => :usefull_table))
|
206
|
+
end
|
207
|
+
end
|
208
|
+
else
|
209
|
+
content_tag(:div, :class => options[:class]) do
|
210
|
+
form_tag( options[:url], :method => :get ) do
|
211
|
+
submit_tag(I18n.t(:submit_excel, :scope => :usefull_table))
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
else
|
216
|
+
#If "" the next div magically disappear...
|
217
|
+
" "
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
#==Table
|
222
|
+
#Draw Table
|
223
|
+
#===Parameters
|
224
|
+
# :table => {
|
225
|
+
# :div_html => {:class => "usefull_table"} #HTML options of <div> container
|
226
|
+
# :header_html] => {:class => "first_row"} #HTML options of Headers <tr>
|
227
|
+
# :html => {} #HTML options of <table>
|
228
|
+
# }
|
229
|
+
def usefull_table_for(builder, object, search, options = {})
|
230
|
+
#Rails::logger.info("TableHelper#usefull_table_for ")
|
231
|
+
content_tag(:div, options[:div_html]) do
|
232
|
+
content_tag(:table, options[:html]) do
|
233
|
+
builder.render_header +
|
234
|
+
builder.render_body
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
239
|
+
def select_path(paths, extension)
|
240
|
+
Rails::logger.info("select_path @path=#{paths.inspect}\n\n")
|
241
|
+
paths.delete_if {|path| !File.exists?(path)}
|
242
|
+
Rails::logger.info("select_path(dopo) @path=#{paths.inspect}\n\n")
|
243
|
+
paths.blank? ? nil : paths.first
|
244
|
+
end
|
245
|
+
|
246
|
+
# Makes an HTML element specified by the DOM ID +field_id+ become an in-place
|
247
|
+
# editor of a property.
|
248
|
+
#
|
249
|
+
# A form is automatically created and displayed when the user clicks the element,
|
250
|
+
# something like this:
|
251
|
+
# <form id="myElement-in-place-edit-form" target="specified url">
|
252
|
+
# <input name="value" text="The content of myElement"/>
|
253
|
+
# <input type="submit" value="ok"/>
|
254
|
+
# <a onclick="javascript to cancel the editing">cancel</a>
|
255
|
+
# </form>
|
256
|
+
#
|
257
|
+
# The form is serialized and sent to the server using an AJAX call, the action on
|
258
|
+
# the server should process the value and return the updated value in the body of
|
259
|
+
# the reponse. The element will automatically be updated with the changed value
|
260
|
+
# (as returned from the server).
|
261
|
+
#
|
262
|
+
# Required +options+ are:
|
263
|
+
# <tt>:url</tt>:: Specifies the url where the updated value should
|
264
|
+
# be sent after the user presses "ok".
|
265
|
+
#
|
266
|
+
# Addtional +options+ are:
|
267
|
+
# <tt>:rows</tt>:: Number of rows (more than 1 will use a TEXTAREA)
|
268
|
+
# <tt>:cols</tt>:: Number of characters the text input should span (works for both INPUT and TEXTAREA)
|
269
|
+
# <tt>:size</tt>:: Synonym for :cols when using a single line text input.
|
270
|
+
# <tt>:cancel_text</tt>:: The text on the cancel link. (default: "cancel")
|
271
|
+
# <tt>:save_text</tt>:: The text on the save link. (default: "ok")
|
272
|
+
# <tt>:loading_text</tt>:: The text to display while the data is being loaded from the server (default: "Loading...")
|
273
|
+
# <tt>:saving_text</tt>:: The text to display when submitting to the server (default: "Saving...")
|
274
|
+
# <tt>:external_control</tt>:: The id of an external control used to enter edit mode.
|
275
|
+
# <tt>:load_text_url</tt>:: URL where initial value of editor (content) is retrieved.
|
276
|
+
# <tt>:options</tt>:: Pass through options to the AJAX call (see prototype's Ajax.Updater)
|
277
|
+
# <tt>:parameters</tt>:: Pass through post
|
278
|
+
# <tt>:with</tt>:: JavaScript snippet that should return what is to be sent
|
279
|
+
# in the AJAX call, +form+ is an implicit parameter
|
280
|
+
# <tt>:script</tt>:: Instructs the in-place editor to evaluate the remote JavaScript response (default: false)
|
281
|
+
# <tt>:click_to_edit_text</tt>::The text shown during mouseover the editable text (default: "Click to edit")
|
282
|
+
def in_place_editor(field_id, options = {})
|
283
|
+
function = "new Ajax.InPlaceEditor("
|
284
|
+
function << "'#{field_id}', "
|
285
|
+
function << "'#{url_for(options[:url])}'"
|
286
|
+
|
287
|
+
js_options = {}
|
288
|
+
|
289
|
+
if protect_against_forgery?
|
290
|
+
options[:with] ||= "Form.serialize(form)"
|
291
|
+
options[:with] += " + '&authenticity_token=' + encodeURIComponent('#{form_authenticity_token}')"
|
292
|
+
options[:parameters].each_pair {|k,v| options[:with] += " + '&#{k.to_s}=' + encodeURIComponent('#{v.to_s}')"} if options[:parameters]
|
293
|
+
end
|
294
|
+
|
295
|
+
|
296
|
+
|
297
|
+
js_options['cancelText'] = %('#{options[:cancel_text]}') if options[:cancel_text]
|
298
|
+
js_options['okText'] = %('#{options[:save_text]}') if options[:save_text]
|
299
|
+
js_options['loadingText'] = %('#{options[:loading_text]}') if options[:loading_text]
|
300
|
+
js_options['savingText'] = %('#{options[:saving_text]}') if options[:saving_text]
|
301
|
+
js_options['rows'] = options[:rows] if options[:rows]
|
302
|
+
js_options['cols'] = options[:cols] if options[:cols]
|
303
|
+
js_options['size'] = options[:size] if options[:size]
|
304
|
+
js_options['externalControl'] = "'#{options[:external_control]}'" if options[:external_control]
|
305
|
+
js_options['loadTextURL'] = "'#{url_for(options[:load_text_url])}'" if options[:load_text_url]
|
306
|
+
js_options['ajaxOptions'] = options[:options] if options[:options]
|
307
|
+
js_options['htmlResponse'] = !options[:script] if options[:script]
|
308
|
+
js_options['callback'] = "function(form) { return #{options[:with]} }" if options[:with]
|
309
|
+
js_options['clickToEditText'] = %('#{options[:click_to_edit_text]}') if options[:click_to_edit_text]
|
310
|
+
js_options['textBetweenControls'] = %('#{options[:text_between_controls]}') if options[:text_between_controls]
|
311
|
+
js_options['onComplete'] = %('#{options[:on_complete]}') if options[:on_complete]
|
312
|
+
js_options['onFailure'] = %('#{options[:on_failure]}') if options[:on_failure]
|
313
|
+
function << (', ' + options_for_javascript(js_options)) unless js_options.empty?
|
314
|
+
|
315
|
+
function << ')'
|
316
|
+
|
317
|
+
javascript_tag(function)
|
318
|
+
end
|
319
|
+
|
320
|
+
|
321
|
+
|
322
|
+
|
323
|
+
end
|