spyro 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|