spyro 0.0.2
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +37 -0
- data/app/assets/OLDjavascripts/application.js +25 -0
- data/app/assets/OLDjavascripts/components.es6 +10 -0
- data/app/assets/OLDjavascripts/components/base/base.es6 +197 -0
- data/app/assets/OLDjavascripts/components/base/collection.es6 +199 -0
- data/app/assets/OLDjavascripts/components/base/element.es6 +134 -0
- data/app/assets/OLDjavascripts/components/base/field.es6 +26 -0
- data/app/assets/OLDjavascripts/components/base/inputs/text.es6 +21 -0
- data/app/assets/OLDjavascripts/components/base/pagination.es6 +23 -0
- data/app/assets/OLDjavascripts/vendor/lodash.js +121 -0
- data/app/assets/OLDjavascripts/vendor/moment-twitter.js +86 -0
- data/app/assets/OLDjavascripts/vendor/moment.js +80 -0
- data/app/assets/OLDjavascripts/vendor/pluralize.js +433 -0
- data/app/views/base/_associations.html.haml +11 -0
- data/app/views/base/_custom.html.haml +0 -0
- data/app/views/base/_details.html.haml +3 -0
- data/app/views/base/_edit_header.html.haml +3 -0
- data/app/views/base/_fields.html.haml +11 -0
- data/app/views/base/_form.html.haml +6 -0
- data/app/views/base/_index_header.html.haml +4 -0
- data/app/views/base/_new_header.html.haml +3 -0
- data/app/views/base/_other_form_fields.html.haml +0 -0
- data/app/views/base/_show_header.html.haml +9 -0
- data/app/views/base/_upload_fields.html.haml +5 -0
- data/app/views/base/copy.html.haml +10 -0
- data/app/views/base/edit.html.haml +4 -0
- data/app/views/base/index.csv.haml +8 -0
- data/app/views/base/index.html.haml +7 -0
- data/app/views/base/index.js.haml +2 -0
- data/app/views/base/index.xls.ruby +12 -0
- data/app/views/base/mailer.html.haml +46 -0
- data/app/views/base/new.html.haml +4 -0
- data/app/views/base/notify.html.haml +11 -0
- data/app/views/base/show.html.haml +8 -0
- data/app/views/base/stats.html.haml +36 -0
- data/app/views/base/trombi.html.haml +1 -0
- data/app/views/base/upload.html.haml +24 -0
- data/config/initializers/assets.rb +1 -0
- data/config/routes.rb +2 -0
- data/lib/spyro.rb +24 -0
- data/lib/spyro/active_record_add_on.rb +38 -0
- data/lib/spyro/application_controller_add_on.rb +24 -0
- data/lib/spyro/collections/outputs/admin_table.rb +28 -0
- data/lib/spyro/collections/outputs/bar_graph_table.rb +46 -0
- data/lib/spyro/collections/outputs/base.rb +23 -0
- data/lib/spyro/collections/outputs/csv.rb +34 -0
- data/lib/spyro/collections/outputs/fields.rb +118 -0
- data/lib/spyro/collections/outputs/flatui_table.rb +40 -0
- data/lib/spyro/collections/outputs/inplace_table.rb +29 -0
- data/lib/spyro/collections/outputs/map.rb +22 -0
- data/lib/spyro/collections/outputs/table.rb +126 -0
- data/lib/spyro/collections/outputs/xlsx.rb +39 -0
- data/lib/spyro/collections/parsers/active_ldap_relation.rb +22 -0
- data/lib/spyro/collections/parsers/active_record_relation.rb +138 -0
- data/lib/spyro/collections/parsers/array.rb +38 -0
- data/lib/spyro/collections/parsers/base.rb +60 -0
- data/lib/spyro/collections/parsers/kaminari_array.rb +38 -0
- data/lib/spyro/collections/parsers/model.rb +31 -0
- data/lib/spyro/controllers/strong_parameted.rb +33 -0
- data/lib/spyro/engine.rb +6 -0
- data/lib/spyro/filters_controller_add_on.rb +161 -0
- data/lib/spyro/helpers/action_view_extension.rb +726 -0
- data/lib/spyro/namespace_template_inheritance.rb +30 -0
- data/lib/spyro/usefull_attributes.rb +14 -0
- data/lib/spyro/version.rb +3 -0
- data/lib/tasks/spyro_tasks.rake +4 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/spyro_test.rb +7 -0
- data/test/test_helper.rb +21 -0
- metadata +256 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
require "csv"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module Spyro
|
|
6
|
+
module ActionViewExtension
|
|
7
|
+
|
|
8
|
+
module CollectionForHelper
|
|
9
|
+
module Output
|
|
10
|
+
class CSV < Output::Base
|
|
11
|
+
|
|
12
|
+
def render_header csv
|
|
13
|
+
return unless @unicollection.meta[:data]
|
|
14
|
+
csv << @unicollection.meta[:data]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def render_body csv
|
|
18
|
+
@unicollection.rows.each do |row|
|
|
19
|
+
csv << row[:data].map(&:value)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def render
|
|
24
|
+
return "" if @unicollection.rows.empty?
|
|
25
|
+
::CSV.generate({}) do |csv|
|
|
26
|
+
render_header csv
|
|
27
|
+
render_body csv
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
module Spyro
|
|
4
|
+
module ActionViewExtension
|
|
5
|
+
|
|
6
|
+
module CollectionForHelper
|
|
7
|
+
module Output
|
|
8
|
+
module Fields
|
|
9
|
+
# Key => [class => object class ; symbol => db_type, string for pattern matching]
|
|
10
|
+
@@fields = { [ActiveSupport::TimeWithZone, ""] => {:method => :datetime},
|
|
11
|
+
[Object, /_prct$/] => {:method => :prct},
|
|
12
|
+
[Float, ""] => {:method => :float},
|
|
13
|
+
[:boolean, ""] => {:method => :boolean},
|
|
14
|
+
[:text, /_html$/] => {:method => :html},
|
|
15
|
+
[:text, /code$/] => {:method => :html},
|
|
16
|
+
[:text, ""] => {:method => :text},
|
|
17
|
+
[String, /_url$/] => {:method => :url},
|
|
18
|
+
#[String, /_email$/] => {:method => :email},
|
|
19
|
+
[String, ""] => {:method => :string}, }
|
|
20
|
+
|
|
21
|
+
@@fields[[CarrierWave::Uploader::Base, /_image$/]] = {:method => :cw_image} if defined? CarrierWave and defined? CarrierWave::Uploader and defined? CarrierWave::Uploader::Base
|
|
22
|
+
@@fields[[CarrierWave::Uploader::Base, ""]] = {:method => :cw_file} if defined? CarrierWave and defined? CarrierWave::Uploader and defined? CarrierWave::Uploader::Base
|
|
23
|
+
@@fields[[ClassyEnum::Base, ""]] = {:method => :classy_enum} if defined? ClassyEnum
|
|
24
|
+
|
|
25
|
+
@@fields[[Object, ""]] = {:method => :default}
|
|
26
|
+
|
|
27
|
+
delegate :l, :link_to, :mail_to, :cw_image_tag, :truncate, :strip_tags, :progress, to: :@h
|
|
28
|
+
|
|
29
|
+
def format_default value, options
|
|
30
|
+
value.to_s
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def format_classy_enum value, options
|
|
34
|
+
value.blank? ? "" : value.text
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def format_datetime value, options
|
|
38
|
+
l(value, :format => options[:format] || :datetime)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def format_cw_image value, options
|
|
42
|
+
cw_image_tag value, options[:version]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def format_cw_file value, options
|
|
46
|
+
link_to value.file.filename, value.url unless value.file.nil?
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def format_email value, options
|
|
50
|
+
mail_to value
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def format_boolean value, options
|
|
54
|
+
value ? "Yes" : "No"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def format_period values, options
|
|
58
|
+
begin_at, end_at, current = *values
|
|
59
|
+
current ||= Time.zone.now
|
|
60
|
+
|
|
61
|
+
total, actual = (end_at.to_i - begin_at.to_i), (current.to_i - begin_at.to_i)
|
|
62
|
+
current_percentage = [0, 100, (actual * 100) / total].sort.second
|
|
63
|
+
<<EOP
|
|
64
|
+
<div class="col-md-12">
|
|
65
|
+
<span class="date-before col-md-6 pull-left">#{l(begin_at, :format => options[:format] || :datetime)}</span>
|
|
66
|
+
<span class="date-after col-md-6 pull-right">#{l(end_at, :format => options[:format] || :datetime)}</span>
|
|
67
|
+
<div class="col-md-10 col-md-offset-1">
|
|
68
|
+
#{progress current_percentage}
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
EOP
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def format_progress values, options
|
|
76
|
+
actual, total = *values
|
|
77
|
+
current_percentage = [0, 100, (actual * 100) / total].sort.second rescue 0
|
|
78
|
+
<<EOP
|
|
79
|
+
<div class="col-md-12">
|
|
80
|
+
<div class="col-md-12 percentage-label">
|
|
81
|
+
#{actual} / #{total}
|
|
82
|
+
</div>
|
|
83
|
+
<div class="col-md-10 col-md-offset-1">
|
|
84
|
+
#{progress current_percentage}
|
|
85
|
+
</div>
|
|
86
|
+
</div>
|
|
87
|
+
EOP
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def format_prct value, options
|
|
92
|
+
value ? ("%.2f%%" % value) : "N/A"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def format_float value, options
|
|
96
|
+
value ? ("%.2f" % value) : "N/A"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def format_url value, options
|
|
100
|
+
link_to value, (value.start_with?('http') ? value : ('http://' + value))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def format_html value, options
|
|
104
|
+
"<span class='has-popover' data-html='true' data-content='#{@h.send(:h, value.to_s)}'>#{@h.truncate(@h.strip_tags(HTMLEntities.new.decode(value.to_s)), :length => 40, :separator => ' ')}</span>".html_safe
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def format_text value, options
|
|
108
|
+
"<span class='has-popover' data-content='#{@h.send(:h, value.to_s)}'>#{@h.truncate(value.to_s, :length => 40, :separator => ' ')}</span>".html_safe
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def format_string value, options
|
|
112
|
+
value.to_s
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require_relative "table"
|
|
2
|
+
|
|
3
|
+
module Spyro
|
|
4
|
+
module ActionViewExtension
|
|
5
|
+
module CollectionForHelper
|
|
6
|
+
module Output
|
|
7
|
+
class FlatuiTable < Table
|
|
8
|
+
delegate :link_to, :button, :button_success, :button_danger, :button_info, to: :@h
|
|
9
|
+
|
|
10
|
+
def initialize unicollection, helper, parser_class
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render_cell_buttons row
|
|
15
|
+
row[:meta][:actions] = {} if row[:meta][:actions].nil?
|
|
16
|
+
|
|
17
|
+
html = if row[:meta][:actions].is_a? Hash
|
|
18
|
+
row[:meta][:actions].map do |name, link|
|
|
19
|
+
case name
|
|
20
|
+
when :show
|
|
21
|
+
button_success "", link, :icon => :search, :class => 'btn btn-lg'
|
|
22
|
+
when :edit
|
|
23
|
+
button_info "", link, :icon => :edit, :class => "btn btn-lg"
|
|
24
|
+
when :destroy
|
|
25
|
+
button_danger "", link, default_destroy_link_attributes.merge(:icon => :trash, :class => "btn btn-lg")
|
|
26
|
+
else
|
|
27
|
+
button "", link, :icon => :name, :class => "btn btn-lg"
|
|
28
|
+
end
|
|
29
|
+
end.join ''
|
|
30
|
+
else
|
|
31
|
+
row[:meta][:actions]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
"<td>#{html}</td>"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require_relative "table"
|
|
2
|
+
|
|
3
|
+
module Spyro
|
|
4
|
+
module ActionViewExtension
|
|
5
|
+
|
|
6
|
+
module CollectionForHelper
|
|
7
|
+
module Output
|
|
8
|
+
class InplaceTable < Table
|
|
9
|
+
def initialize unicollection, helper, parser_class
|
|
10
|
+
raise "InplaceTable: Bad parser class (#{parser_class} instead of CollectionForHelper::Parser::Model)" if parser_class != CollectionForHelper::Parser::Model
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def data_type elem
|
|
15
|
+
"input"
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def custom_value_formatted value, elem
|
|
19
|
+
if elem.name.to_sym.in? [:header, :id, :created_at, :updated_at]
|
|
20
|
+
value
|
|
21
|
+
else
|
|
22
|
+
"<span class='best_in_place' data-type='#{data_type elem}' data-url='#{@unicollection.meta[:show]}' data-object='#{@unicollection.meta[:model_class].to_s.underscore}' data-attribute='#{elem.name}' data-type='input'>#{value}</span>"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Spyro
|
|
4
|
+
module ActionViewExtension
|
|
5
|
+
|
|
6
|
+
module CollectionForHelper
|
|
7
|
+
module Output
|
|
8
|
+
class Map < Output::Base
|
|
9
|
+
delegate :image_tag, to: :@h
|
|
10
|
+
|
|
11
|
+
def render
|
|
12
|
+
locations = @unicollection.rows.map do |r|
|
|
13
|
+
r[:data].map(&:value).join(', ')
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
image_tag "http://maps.googleapis.com/maps/api/staticmap?size=600x300&maptype=roadmap&sensor=false&#{locations.map {|location| "markers=#{location}"}.join('&')}"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
require_relative "fields"
|
|
3
|
+
|
|
4
|
+
module Spyro
|
|
5
|
+
module ActionViewExtension
|
|
6
|
+
|
|
7
|
+
module CollectionForHelper
|
|
8
|
+
module Output
|
|
9
|
+
class Table < Output::Base
|
|
10
|
+
delegate :link_to, :mini_button, :mini_button_success, :mini_button_danger, :mini_button_info, to: :@h
|
|
11
|
+
|
|
12
|
+
include Fields
|
|
13
|
+
|
|
14
|
+
def header
|
|
15
|
+
@header ||= (@unicollection.meta[:header] || []) + (@unicollection.meta[:actions] ? ['Actions'] : [])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def render_header
|
|
19
|
+
return "" unless @unicollection.meta[:header]
|
|
20
|
+
content_tag :thead, @unicollection.meta[:html_header] do
|
|
21
|
+
html = header.map do |header_sym|
|
|
22
|
+
header = t(header_sym)
|
|
23
|
+
header = @unicollection.meta[:block_header].call header_sym, header if @unicollection.meta[:block_header]
|
|
24
|
+
"<th>#{header}</th>"
|
|
25
|
+
end.join('')
|
|
26
|
+
"<tr>#{html}</tr>".html_safe
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def default_destroy_link_attributes
|
|
31
|
+
{:data => {:confirm => "Are you sure?", :method => "delete", :'confirm-title' => "Confirmation"}}
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def render_cell_buttons row
|
|
35
|
+
row[:meta][:actions] = {} if row[:meta][:actions].nil?
|
|
36
|
+
|
|
37
|
+
html = if row[:meta][:actions].is_a? Hash
|
|
38
|
+
(row[:meta][:actions] || []).map do |name, link|
|
|
39
|
+
case name
|
|
40
|
+
when :show
|
|
41
|
+
mini_button_success name, link
|
|
42
|
+
when :edit
|
|
43
|
+
mini_button_info name, link
|
|
44
|
+
when :destroy
|
|
45
|
+
mini_button_danger name, link, default_destroy_link_attributes
|
|
46
|
+
else
|
|
47
|
+
mini_button name, link
|
|
48
|
+
end
|
|
49
|
+
end.join ''
|
|
50
|
+
else
|
|
51
|
+
row[:meta][:actions]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
"<td><span class='btn-group'>#{html}</span></td>"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def format_value value, elem
|
|
58
|
+
return self.send("format_#{elem.as}".to_sym, value, {}) if elem.as
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@@fields.each do |keys, values|
|
|
62
|
+
klass, pattern = *keys
|
|
63
|
+
if (Symbol === klass and klass == elem.db_type) or (Class === klass and value.is_a? klass)
|
|
64
|
+
return self.send("format_#{values[:method]}".to_sym, value, {}) if elem.name.to_s.match pattern
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
value
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def custom_value_formatted value, elem
|
|
71
|
+
value
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def render_body
|
|
75
|
+
content = @unicollection.rows.map do |row|
|
|
76
|
+
html = row[:data].map do |elem|
|
|
77
|
+
value_formatted = elem.value
|
|
78
|
+
value_formatted = t(value_formatted) if elem.translate
|
|
79
|
+
value_formatted = format_value value_formatted, elem
|
|
80
|
+
value_formatted = link_to value_formatted, elem.link if elem.link
|
|
81
|
+
value_formatted = custom_value_formatted value_formatted, elem
|
|
82
|
+
elem.html ? content_tag(:td, value_formatted, elem.html) : "<td>#{value_formatted}</td>"
|
|
83
|
+
end.join('')
|
|
84
|
+
html += render_cell_buttons row if @unicollection.meta[:actions]
|
|
85
|
+
(row[:meta][:opts] and row[:meta][:opts][:html]) ? content_tag(:tr, html.html_safe, row[:meta][:opts][:html]) : "<tr>#{html}</tr>"
|
|
86
|
+
end.join('').html_safe
|
|
87
|
+
|
|
88
|
+
if @unicollection.meta[:header]
|
|
89
|
+
content_tag :tbody, @unicollection.meta[:html_body] do
|
|
90
|
+
content
|
|
91
|
+
end
|
|
92
|
+
else
|
|
93
|
+
content
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def render_footer
|
|
98
|
+
return "" unless @unicollection.meta[:footer] and @unicollection.meta[:header]
|
|
99
|
+
|
|
100
|
+
total = header.count
|
|
101
|
+
|
|
102
|
+
content_tag :tfoot, @unicollection.meta[:html_footer] do
|
|
103
|
+
content = @unicollection.meta[:footer].map do |elem|
|
|
104
|
+
colspan = [(header.count / @unicollection.meta[:footer].count.to_f).ceil, total].min
|
|
105
|
+
total -= colspan
|
|
106
|
+
"<td colspan='#{colspan}'>#{elem}</td>"
|
|
107
|
+
end.join('')
|
|
108
|
+
"<tr>#{content}</tr>".html_safe
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def render
|
|
113
|
+
return "" if @unicollection.rows.empty?
|
|
114
|
+
table_html_opts = {:class => ['table', self.class.to_s.demodulize.underscore]}.deep_merge(@unicollection.meta[:html] || {}) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
|
|
115
|
+
content_tag :table, table_html_opts do
|
|
116
|
+
html = render_header.html_safe
|
|
117
|
+
html << render_body
|
|
118
|
+
html << render_footer
|
|
119
|
+
html
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Spyro
|
|
4
|
+
module ActionViewExtension
|
|
5
|
+
|
|
6
|
+
module CollectionForHelper
|
|
7
|
+
module Output
|
|
8
|
+
class XLSX < Output::Base
|
|
9
|
+
def render_header sheet
|
|
10
|
+
return unless @unicollection.meta[:data]
|
|
11
|
+
sheet.add_row @unicollection.meta[:data]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def render_body sheet
|
|
15
|
+
@unicollection.rows.each do |row|
|
|
16
|
+
sheet.add_row row[:data].map(&:value)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def render
|
|
21
|
+
return "" if @unicollection.rows.empty?
|
|
22
|
+
|
|
23
|
+
filename = @unicollection.meta[:filename] || @unicollection.meta[:model_class] || "file"
|
|
24
|
+
xlsx_package = Axlsx::Package.new({})
|
|
25
|
+
wb = xlsx_package.workbook
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
wb.add_worksheet(name: filename) do |sheet|
|
|
29
|
+
render_header sheet
|
|
30
|
+
render_body sheet
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
xlsx_package.to_stream.string
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# require_relative "base"
|
|
2
|
+
# require_relative "active_record_relation"
|
|
3
|
+
# require_relative "../../../app/models/active_ldap"
|
|
4
|
+
|
|
5
|
+
# module Spyro
|
|
6
|
+
# module ActionViewExtension
|
|
7
|
+
|
|
8
|
+
# module CollectionForHelper
|
|
9
|
+
# module Parser
|
|
10
|
+
# class ActiveLdapRelation < ActiveRecordRelation
|
|
11
|
+
# @@types[::ActiveLDAP::Relation] = self
|
|
12
|
+
|
|
13
|
+
# def initialize *args
|
|
14
|
+
# super
|
|
15
|
+
|
|
16
|
+
# header [:id, :login, :email], :actions => true
|
|
17
|
+
# end
|
|
18
|
+
# end
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require_relative "base"
|
|
2
|
+
|
|
3
|
+
module Spyro
|
|
4
|
+
module ActionViewExtension
|
|
5
|
+
|
|
6
|
+
module CollectionForHelper
|
|
7
|
+
module Parser
|
|
8
|
+
class ActiveRecordRelation < Parser::Base
|
|
9
|
+
@@types[::ActiveRecord::Relation] = self
|
|
10
|
+
|
|
11
|
+
def initialize collection, helper, options
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def header args, opts = {}, &block
|
|
16
|
+
self.data args, opts, &block
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def data args, opts = {}, &block
|
|
20
|
+
if args.is_a? ::Array
|
|
21
|
+
@unicollection.add_meta :data, args
|
|
22
|
+
else
|
|
23
|
+
@unicollection.add_meta :data, args.values.reduce(:+).uniq
|
|
24
|
+
args.each do |key, value|
|
|
25
|
+
@unicollection.add_meta "data-#{key}".to_sym, value
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
self.actions if opts[:actions]
|
|
30
|
+
@unicollection.add_meta :html_header, opts[:html]
|
|
31
|
+
@unicollection.add_meta :block_header, block if block_given?
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def parse
|
|
35
|
+
unless @unicollection.has_meta? :data
|
|
36
|
+
@unicollection.add_meta :data, @collection.first.try(:attribute_names).try(:compact) || []
|
|
37
|
+
@unicollection.add_meta :actions, true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if @unicollection.rows.empty?
|
|
41
|
+
@collection.each do |model|
|
|
42
|
+
@unicollection.meta[:model_class] ||= model.class.to_s
|
|
43
|
+
|
|
44
|
+
@unicollection.row do |r|
|
|
45
|
+
@unicollection.meta[:data].each do |name|
|
|
46
|
+
hash = hash_for_name model, name
|
|
47
|
+
hash[:link] = link model if name == :name
|
|
48
|
+
r.add_elem UniData::Element.new(hash)
|
|
49
|
+
end
|
|
50
|
+
r.add_elem_meta :actions, populate_actions(model, r, @options, [:show, :edit, :destroy])
|
|
51
|
+
r.add_elem_meta :id, model.id
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
@unicollection.add_meta :header, @unicollection.meta[:data]
|
|
57
|
+
@unicollection.try_add_meta :footer, ["Total: #{@unicollection.rows.count}"]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def footer content, opts = {}
|
|
61
|
+
@unicollection.add_meta :footer, [*content]
|
|
62
|
+
@unicollection.add_meta :html_footer, opts[:html]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def populate_actions model, row, options, buttons
|
|
66
|
+
actions = {}
|
|
67
|
+
|
|
68
|
+
buttons.each do |button|
|
|
69
|
+
actions[:show] = polymorphic_path([*options[:parents], model]) rescue nil if button == :show
|
|
70
|
+
actions[:edit] = (actions[:show] ? "#{actions[:show]}/edit" : edit_polymorphic_path([*options[:parents], model])) rescue nil if button == :edit
|
|
71
|
+
actions[:destroy] = actions[:show] || polymorphic_path([*options[:parents], model]) rescue nil if button == :destroy
|
|
72
|
+
actions[button.keys.first] = button.values.first if button.is_a? Hash
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
actions.delete_if { |_, v| v.nil? }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def actions val = true
|
|
79
|
+
@unicollection.add_meta :actions, val
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def body opts = {}, &block
|
|
83
|
+
def row opts
|
|
84
|
+
@r.add_elem_meta :opts, opts
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
@collection.each do |elem|
|
|
88
|
+
@unicollection.meta[:model_class] ||= elem.class.to_s
|
|
89
|
+
@unicollection.row do |r|
|
|
90
|
+
@elem = elem
|
|
91
|
+
@r = r
|
|
92
|
+
r.add_elem_meta :id, elem.id if elem.respond_to?(:id)
|
|
93
|
+
block.call elem
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
@unicollection.add_meta :html_body, opts[:html]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def cell value = nil, options = {}, &block
|
|
101
|
+
if value.is_a? Hash
|
|
102
|
+
options = value
|
|
103
|
+
value = nil
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
value = @h.capture(&block) || "" if block_given?
|
|
107
|
+
|
|
108
|
+
options[:link] = true if @unicollection.meta[:data] and @unicollection.meta[:data][@unicollection.rows.last[:data].count] == :name
|
|
109
|
+
options[:link] = link @elem if options[:link] == true
|
|
110
|
+
|
|
111
|
+
hash = if value
|
|
112
|
+
{value: value, type: String, name: "custom", db_type: String}
|
|
113
|
+
else
|
|
114
|
+
hash_for_name @elem, @unicollection.meta[:data][@unicollection.rows.last[:data].count]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
@r.add_elem UniData::Element.new(hash.merge(options))
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def buttons buttons = nil, opts = {}, &block
|
|
121
|
+
if block_given?
|
|
122
|
+
@r.add_elem_meta :actions, @h.capture(&block)
|
|
123
|
+
else
|
|
124
|
+
buttons = :all if buttons.nil?
|
|
125
|
+
buttons = [*buttons]
|
|
126
|
+
buttons.map! {|b| b == :all ? [:show, :edit, :destroy] : b}
|
|
127
|
+
buttons.flatten!
|
|
128
|
+
@r.add_elem_meta :actions, populate_actions(@elem, @r, @options, [*buttons])
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
alias_method :button, :buttons
|
|
133
|
+
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|