para 0.6.3 → 0.6.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/para/admin/job-tracker.coffee +1 -1
- data/app/assets/javascripts/para/admin/tabs.coffee +14 -8
- data/app/assets/javascripts/para/admin.js +20 -0
- data/app/assets/javascripts/para/plugins-includes.js.erb +1 -0
- data/app/assets/stylesheets/para/admin.sass +1 -0
- data/app/assets/stylesheets/para/plugins-includes.sass.erb +1 -0
- data/app/controllers/concerns/para/admin/resource_controller_concerns.rb +8 -2
- data/app/controllers/para/admin/crud_resources_controller.rb +1 -1
- data/app/controllers/para/admin/exports_controller.rb +1 -1
- data/app/controllers/para/admin/resources_controller.rb +7 -2
- data/app/decorators/para/component/base_decorator.rb +2 -2
- data/app/helpers/para/admin/pagination_helper.rb +31 -0
- data/app/helpers/para/model_helper.rb +14 -4
- data/app/models/application_record.rb +3 -0
- data/app/models/para/cache/item.rb +27 -0
- data/app/models/para/page/section.rb +0 -6
- data/app/views/para/admin/resources/_exports_menu.html.haml +2 -2
- data/app/views/para/admin/resources/_list.html.haml +1 -1
- data/app/views/para/admin/resources/_per_page_select.html.haml +10 -0
- data/app/views/para/inputs/_nested_many.html.haml +1 -1
- data/app/views/para/inputs/nested_many/_add_with_subclasses.html.haml +1 -1
- data/config/locales/fr.yml +1 -0
- data/db/migrate/20161006105728_create_para_cache_items.rb +12 -0
- data/lib/generators/para/admin_user/admin_user_generator.rb +2 -1
- data/lib/generators/para/exporter/exporter_generator.rb +1 -5
- data/lib/generators/para/exporter/templates/base_exporter.rb +18 -12
- data/lib/generators/para/exporter/templates/csv_exporter.rb +35 -11
- data/lib/generators/para/exporter/templates/xls_exporter.rb +48 -0
- data/lib/generators/para/orderable/orderable_generator.rb +1 -1
- data/lib/generators/para/page/section/section_generator.rb +1 -1
- data/lib/para/attribute_field/base.rb +4 -0
- data/lib/para/attribute_field/datetime.rb +1 -1
- data/lib/para/attribute_field/file.rb +4 -0
- data/lib/para/attribute_field/image.rb +4 -0
- data/lib/para/cache/database_store.rb +71 -0
- data/lib/para/cache.rb +11 -0
- data/lib/para/config.rb +28 -2
- data/lib/para/engine.rb +9 -14
- data/lib/para/exporter/base.rb +26 -0
- data/lib/para/exporter/csv.rb +6 -26
- data/lib/para/exporter/table.rb +23 -0
- data/lib/para/exporter/xls.rb +59 -0
- data/lib/para/exporter.rb +6 -3
- data/lib/para/ext.rb +0 -1
- data/lib/para/form_builder/containers.rb +14 -1
- data/lib/para/form_builder.rb +1 -0
- data/lib/para/importer/base.rb +2 -28
- data/lib/para/inputs/nested_many_input.rb +9 -4
- data/lib/para/job/base.rb +23 -4
- data/lib/para/logging/active_job_log_subscriber.rb +2 -0
- data/lib/para/orderable.rb +2 -2
- data/lib/para/plugins/set.rb +34 -0
- data/lib/para/plugins.rb +3 -2
- data/lib/para/routing/component_controller_constraint.rb +1 -1
- data/lib/para/routing/component_name_constraint.rb +22 -0
- data/lib/para/routing.rb +1 -0
- data/lib/para/sti/root_model.rb +4 -54
- data/lib/para/version.rb +1 -1
- data/lib/para.rb +4 -1
- data/lib/rails/routing_mapper.rb +67 -34
- data/vendor/assets/javascripts/html5-sortable.js +142 -0
- data/vendor/assets/javascripts/jasny.bootstrap.min.js +7 -0
- data/vendor/assets/javascripts/jquery.remote-modal-form.coffee +67 -0
- data/vendor/assets/javascripts/jquery.scrollto.js +187 -0
- data/vendor/assets/stylesheets/animate.min.css +6 -0
- data/vendor/assets/stylesheets/jasny.bootstrap.min.css +7 -0
- metadata +56 -9
- data/app/assets/javascripts/para/admin.coffee +0 -19
- data/lib/para/ext/simple_form_extension.rb +0 -27
@@ -0,0 +1,71 @@
|
|
1
|
+
# This is a simple ActiveSupport::Cache::Store implementation, borrowed from
|
2
|
+
# activesupport-db-cache gem (https://github.com/sergio-fry/activesupport-db-cache),
|
3
|
+
# simplified.
|
4
|
+
#
|
5
|
+
# It also adds RequestStore.store caching, avoiding same key reads to hit
|
6
|
+
# ActiveRecord multiple times in a single request
|
7
|
+
#
|
8
|
+
# This is primarily meant to manage jobs status storing in Para::Job::Base
|
9
|
+
# through the ActiveJob::Status gem. It allows not to add external storage
|
10
|
+
# systems dependency (redis, memcache) to the app when not needed (when using
|
11
|
+
# default ActiveJob 5 AsyncAdapter or SuckerPunchAdapter).
|
12
|
+
#
|
13
|
+
# Since it's quite slow, it's advised to replace it with faster cache stores
|
14
|
+
# like Redis or Memcache when used in large production systems.
|
15
|
+
#
|
16
|
+
module Para
|
17
|
+
module Cache
|
18
|
+
class DatabaseStore < ActiveSupport::Cache::Store
|
19
|
+
def clear
|
20
|
+
Item.delete_all
|
21
|
+
end
|
22
|
+
|
23
|
+
def delete_entry(key, options)
|
24
|
+
Item.delete_all(key: key)
|
25
|
+
end
|
26
|
+
|
27
|
+
def read_entry(key, options={})
|
28
|
+
RequestStore.store[cache_key_for(key)] ||= Item.find_by(key: key)
|
29
|
+
end
|
30
|
+
|
31
|
+
def write_entry(key, entry, options)
|
32
|
+
RequestStore.store[cache_key_for(key)] ||= Item.where(key: key).first_or_initialize
|
33
|
+
item = RequestStore.store[cache_key_for(key)]
|
34
|
+
|
35
|
+
options = options.clone.symbolize_keys
|
36
|
+
|
37
|
+
item.value = entry.value
|
38
|
+
item.expires_at = options[:expires_in].try(:since)
|
39
|
+
item.save!
|
40
|
+
|
41
|
+
# Ensure cached item in RequestStore is up to date
|
42
|
+
RequestStore.store[cache_key_for(key)] = item
|
43
|
+
rescue ActiveRecord::RecordNotUnique
|
44
|
+
ensure
|
45
|
+
clear_expired_keys
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def clear_expired_keys
|
51
|
+
if Item.count > Para.config.database_cache_store_max_items
|
52
|
+
remove_expired_items
|
53
|
+
remove_old_items
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def remove_expired_items
|
58
|
+
Item.where("expires_at < ?", Time.now).delete_all
|
59
|
+
end
|
60
|
+
|
61
|
+
def remove_old_items
|
62
|
+
count = (Item.count - Para.config.database_cache_store_max_items)
|
63
|
+
Item.order('updated_at ASC').limit(count).delete_all if count > 0
|
64
|
+
end
|
65
|
+
|
66
|
+
def cache_key_for(key)
|
67
|
+
['para.cache.database_store', key].join('.')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/para/cache.rb
ADDED
data/lib/para/config.rb
CHANGED
@@ -18,8 +18,13 @@ module Para
|
|
18
18
|
mattr_accessor :resource_name_methods
|
19
19
|
@@resource_name_methods = [:admin_name, :admin_title, :name, :title]
|
20
20
|
|
21
|
-
|
22
|
-
@@plugins =
|
21
|
+
mattr_reader :plugins
|
22
|
+
@@plugins = Para::Plugins::Set.new
|
23
|
+
|
24
|
+
def self.plugins=(array)
|
25
|
+
# Add each item in array to the existing plugins set
|
26
|
+
array.each(&plugins.method(:<<))
|
27
|
+
end
|
23
28
|
|
24
29
|
# Hidden from initializer on purpose.
|
25
30
|
#
|
@@ -31,6 +36,27 @@ module Para
|
|
31
36
|
mattr_accessor :page_actions
|
32
37
|
@@page_actions = {}
|
33
38
|
|
39
|
+
# Allows changing default cache store used by Para to store jobs through
|
40
|
+
# the ActiveJob::Status gem
|
41
|
+
#
|
42
|
+
def self.jobs_store=(store)
|
43
|
+
@@jobs_store = store
|
44
|
+
ActiveJob::Status.store = store
|
45
|
+
end
|
46
|
+
|
47
|
+
# Default to use Para::Cache::DatabaseStore, allowing cross process and
|
48
|
+
# app instances job status sharing
|
49
|
+
#
|
50
|
+
def self.jobs_store
|
51
|
+
@@jobs_store ||= Para::Cache::DatabaseStore.new
|
52
|
+
end
|
53
|
+
|
54
|
+
# The DatabaseStore cache system tries to clean up old keys when reaching
|
55
|
+
# that limit after writing new keys
|
56
|
+
#
|
57
|
+
mattr_accessor :database_cache_store_max_items
|
58
|
+
@@database_cache_store_max_items = 10000
|
59
|
+
|
34
60
|
# Allows accessing plugins root module to configure them through a method
|
35
61
|
# from the Para::Config class.
|
36
62
|
#
|
data/lib/para/engine.rb
CHANGED
@@ -48,12 +48,11 @@ module Para
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
initializer '
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
51
|
+
initializer 'Add resource name methods to simple form extension' do
|
52
|
+
::SimpleFormExtension.resource_name_methods = (
|
53
|
+
Para.config.resource_name_methods +
|
54
|
+
::SimpleFormExtension.resource_name_methods
|
55
|
+
).uniq
|
57
56
|
end
|
58
57
|
|
59
58
|
initializer 'Extend active job status\' status class' do
|
@@ -72,19 +71,15 @@ module Para
|
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
75
|
-
initializer 'Load page sections' do |app|
|
76
|
-
app.config.to_prepare do
|
77
|
-
Para::Page::Section.eager_load!
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
74
|
initializer 'Check for extensions installation' do
|
82
75
|
Para::PostgresExtensionsChecker.check_all
|
83
76
|
end
|
84
77
|
|
85
78
|
initializer 'Configure ActiveJob' do
|
86
|
-
if ActiveSupport::Cache::NullStore === ActiveJob::Status.store
|
87
|
-
|
79
|
+
if ActiveSupport::Cache::NullStore === ActiveJob::Status.store ||
|
80
|
+
ActiveSupport::Cache::MemoryStore === ActiveJob::Status.store
|
81
|
+
then
|
82
|
+
ActiveJob::Status.store = Para.config.jobs_store
|
88
83
|
end
|
89
84
|
|
90
85
|
Para::Logging::ActiveJobLogSubscriber.attach_to :active_job
|
data/lib/para/exporter/base.rb
CHANGED
@@ -25,6 +25,28 @@ module Para
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
+
def render
|
29
|
+
Tempfile.new([name, extension]).tap do |file|
|
30
|
+
file.binmode if binary?
|
31
|
+
file.write(generate)
|
32
|
+
file.rewind
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate
|
37
|
+
fail NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
# Default to writing string data to the exported file, allowing
|
41
|
+
# subclasses to write binary data if needed
|
42
|
+
def binary?
|
43
|
+
false
|
44
|
+
end
|
45
|
+
|
46
|
+
def total_progress
|
47
|
+
resources.length
|
48
|
+
end
|
49
|
+
|
28
50
|
# Allow passing a `:resources` option or a ransack search hash to filter
|
29
51
|
# exported resources
|
30
52
|
#
|
@@ -37,6 +59,10 @@ module Para
|
|
37
59
|
model.all
|
38
60
|
end
|
39
61
|
end
|
62
|
+
|
63
|
+
def encode(string)
|
64
|
+
string.presence && string.to_s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
|
65
|
+
end
|
40
66
|
end
|
41
67
|
end
|
42
68
|
end
|
data/lib/para/exporter/csv.rb
CHANGED
@@ -2,43 +2,23 @@ require 'csv'
|
|
2
2
|
|
3
3
|
module Para
|
4
4
|
module Exporter
|
5
|
-
class Csv <
|
6
|
-
|
7
|
-
|
5
|
+
class Csv < Table
|
6
|
+
protected
|
7
|
+
|
8
|
+
def generate
|
9
|
+
CSV.generate do |csv|
|
8
10
|
csv << headers
|
9
11
|
|
10
12
|
resources.each do |resource|
|
11
13
|
csv << row_for(resource)
|
14
|
+
progress!
|
12
15
|
end
|
13
16
|
end
|
14
|
-
|
15
|
-
Tempfile.new([name, extension]).tap do |file|
|
16
|
-
file.write(data)
|
17
|
-
file.rewind
|
18
|
-
end
|
19
17
|
end
|
20
18
|
|
21
|
-
private
|
22
|
-
|
23
19
|
def extension
|
24
20
|
'.csv'
|
25
21
|
end
|
26
|
-
|
27
|
-
def headers
|
28
|
-
fields.map do |field|
|
29
|
-
encode(model.human_attribute_name(field))
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
def row_for(resource)
|
34
|
-
fields.map do |field|
|
35
|
-
encode(resource.send(field))
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def encode(string)
|
40
|
-
string.presence && string.to_s.encode('UTF-8')
|
41
|
-
end
|
42
22
|
end
|
43
23
|
end
|
44
24
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# This class serves as a basic superclass for tabular data specific exports,
|
2
|
+
# which are organized as tables : a header row and several rows of data.
|
3
|
+
#
|
4
|
+
# This allows to only define the `#fields` method in the subclass and let the
|
5
|
+
# exporter work alone
|
6
|
+
#
|
7
|
+
module Para
|
8
|
+
module Exporter
|
9
|
+
class Table < Para::Exporter::Base
|
10
|
+
def headers
|
11
|
+
fields.map do |field|
|
12
|
+
encode(model.human_attribute_name(field))
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def row_for(resource)
|
17
|
+
fields.map do |field|
|
18
|
+
encode(resource.send(field))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
require 'spreadsheet'
|
3
|
+
|
4
|
+
module Para
|
5
|
+
module Exporter
|
6
|
+
class Xls < Table
|
7
|
+
protected
|
8
|
+
|
9
|
+
def extension
|
10
|
+
'.xls'
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
'export'
|
15
|
+
end
|
16
|
+
|
17
|
+
def mime_type
|
18
|
+
'application/vnd.ms-excel'
|
19
|
+
end
|
20
|
+
|
21
|
+
def binary?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate
|
26
|
+
generate_workbook do |workbook|
|
27
|
+
sheet = workbook.create_worksheet
|
28
|
+
|
29
|
+
# Add headers
|
30
|
+
sheet.row(0).concat headers
|
31
|
+
|
32
|
+
# Add content rows
|
33
|
+
resources.each_with_index do |resource , index|
|
34
|
+
sheet.row(index + 1).concat row_for(resource)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate_workbook(&block)
|
40
|
+
workbook = Spreadsheet::Workbook.new
|
41
|
+
|
42
|
+
block.call(workbook)
|
43
|
+
|
44
|
+
buffer = StringIO.new
|
45
|
+
workbook.write(buffer)
|
46
|
+
buffer.rewind
|
47
|
+
buffer.read
|
48
|
+
end
|
49
|
+
|
50
|
+
def fields
|
51
|
+
fail NotImplementedError
|
52
|
+
end
|
53
|
+
|
54
|
+
def encode(string)
|
55
|
+
string.presence && string.to_s.encode('UTF-8', invalid: :replace, undef: :replace, replace: '?')
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/para/exporter.rb
CHANGED
data/lib/para/ext.rb
CHANGED
@@ -49,7 +49,20 @@ module Para
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def para_submit_and_edit_button
|
52
|
-
|
52
|
+
# Create a hidden field that will hold the last tab used by the user,
|
53
|
+
# allowing redirection and re-rendering to display it directly
|
54
|
+
current_anchor_tag = template.hidden_field_tag(
|
55
|
+
:_current_anchor, template.params[:_current_anchor],
|
56
|
+
data: { :'current-anchor' => true }
|
57
|
+
)
|
58
|
+
|
59
|
+
button_tag = button(
|
60
|
+
:submit,
|
61
|
+
::I18n.t('para.shared.save_and_edit'),
|
62
|
+
name: '_save_and_edit', class: 'btn-primary'
|
63
|
+
)
|
64
|
+
|
65
|
+
current_anchor_tag + button_tag
|
53
66
|
end
|
54
67
|
|
55
68
|
def para_submit_and_add_another_button
|
data/lib/para/form_builder.rb
CHANGED
data/lib/para/importer/base.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module Para
|
2
2
|
module Importer
|
3
3
|
class Base < Para::Job::Base
|
4
|
-
rescue_from Exception, with: :rescue_exception
|
5
|
-
|
6
4
|
class_attribute :allows_import_errors
|
7
5
|
|
8
6
|
attr_reader :file, :sheet
|
@@ -29,9 +27,9 @@ module Para
|
|
29
27
|
save_errors!
|
30
28
|
end
|
31
29
|
|
32
|
-
|
30
|
+
protected
|
33
31
|
|
34
|
-
def
|
32
|
+
def total_progress
|
35
33
|
sheet.last_row - 1
|
36
34
|
end
|
37
35
|
|
@@ -68,30 +66,6 @@ module Para
|
|
68
66
|
def headers
|
69
67
|
@headers ||= sheet.row(1)
|
70
68
|
end
|
71
|
-
|
72
|
-
def rescue_exception(exception)
|
73
|
-
status.update(status: :failed)
|
74
|
-
|
75
|
-
tag_logger(self.class.name, self.job_id) do
|
76
|
-
ActiveSupport::Notifications.instrument "failed.active_job",
|
77
|
-
adapter: self.class.queue_adapter, job: self, exception: exception
|
78
|
-
end
|
79
|
-
|
80
|
-
if defined?(ExceptionNotifier)
|
81
|
-
ExceptionNotifier.notify_exception(
|
82
|
-
exception, data: {
|
83
|
-
importer: self.class.name,
|
84
|
-
payload: {
|
85
|
-
file_type: file.class,
|
86
|
-
file_id: file.id,
|
87
|
-
file_name: file.attachment_file_name
|
88
|
-
}
|
89
|
-
}
|
90
|
-
)
|
91
|
-
end
|
92
|
-
|
93
|
-
raise exception
|
94
|
-
end
|
95
69
|
end
|
96
70
|
end
|
97
71
|
end
|
@@ -26,7 +26,8 @@ module Para
|
|
26
26
|
dom_identifier: dom_identifier,
|
27
27
|
resources: resources,
|
28
28
|
nested_locals: locals,
|
29
|
-
subclass: subclass
|
29
|
+
subclass: subclass,
|
30
|
+
subclasses: subclasses
|
30
31
|
}
|
31
32
|
)
|
32
33
|
end
|
@@ -49,9 +50,13 @@ module Para
|
|
49
50
|
end
|
50
51
|
|
51
52
|
def subclass
|
52
|
-
@subclass ||= options.fetch(
|
53
|
-
|
54
|
-
|
53
|
+
@subclass ||= options.fetch(:subclass, subclasses.presence)
|
54
|
+
end
|
55
|
+
|
56
|
+
def subclasses
|
57
|
+
options.fetch(
|
58
|
+
:subclasses,
|
59
|
+
(model.try(:descendants) || []).sort_by { |m| m.model_name.human }
|
55
60
|
)
|
56
61
|
end
|
57
62
|
end
|
data/lib/para/job/base.rb
CHANGED
@@ -2,11 +2,13 @@ module Para
|
|
2
2
|
module Job
|
3
3
|
class Base < ActiveJob::Base
|
4
4
|
include ActiveJob::Status
|
5
|
-
# Used to store
|
5
|
+
# Used to store job errors on the object
|
6
6
|
include ActiveModel::Validations
|
7
|
-
# Used to translate
|
7
|
+
# Used to translate job name with rails default `activemodel` i18n keys
|
8
8
|
extend ActiveModel::Translation
|
9
9
|
|
10
|
+
rescue_from Exception, with: :rescue_exception
|
11
|
+
|
10
12
|
before_perform :store_job_type
|
11
13
|
|
12
14
|
protected
|
@@ -33,8 +35,8 @@ module Para
|
|
33
35
|
def ensure_total_progress
|
34
36
|
return if @total_progress
|
35
37
|
|
36
|
-
@total_progress ||= if respond_to?(:
|
37
|
-
progress.total =
|
38
|
+
@total_progress ||= if respond_to?(:total_progress, true)
|
39
|
+
progress.total = total_progress
|
38
40
|
else
|
39
41
|
progress[:total]
|
40
42
|
end
|
@@ -47,6 +49,23 @@ module Para
|
|
47
49
|
status[key]
|
48
50
|
end
|
49
51
|
end
|
52
|
+
|
53
|
+
def rescue_exception(exception)
|
54
|
+
status.update(status: :failed)
|
55
|
+
|
56
|
+
tag_logger(self.class.name, job_id) do
|
57
|
+
ActiveSupport::Notifications.instrument "failed.active_job",
|
58
|
+
adapter: self.class.queue_adapter, job: self, exception: exception
|
59
|
+
end
|
60
|
+
|
61
|
+
if defined?(ExceptionNotifier)
|
62
|
+
ExceptionNotifier.notify_exception(
|
63
|
+
exception, data: { job: self.class.name, payload: arguments }
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
raise exception
|
68
|
+
end
|
50
69
|
end
|
51
70
|
end
|
52
71
|
end
|
data/lib/para/orderable.rb
CHANGED
@@ -3,7 +3,7 @@ module Para
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
scope :ordered, -> { order(
|
6
|
+
scope :ordered, -> { order("#{ table_name }.position ASC") }
|
7
7
|
before_create :orderable_assign_position
|
8
8
|
end
|
9
9
|
|
@@ -11,7 +11,7 @@ module Para
|
|
11
11
|
return if attribute_present?(:position)
|
12
12
|
|
13
13
|
last_resource = self.class.unscoped
|
14
|
-
.
|
14
|
+
.ordered
|
15
15
|
.where.not(position: nil)
|
16
16
|
.select(:position)
|
17
17
|
.first
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Para
|
2
|
+
module Plugins
|
3
|
+
class Set
|
4
|
+
include Enumerable
|
5
|
+
|
6
|
+
attr_accessor :items
|
7
|
+
|
8
|
+
delegate :+, :<<, :each, to: :items
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@items = []
|
12
|
+
end
|
13
|
+
|
14
|
+
def javascript_includes
|
15
|
+
each_with_object([]) do |plugin, collection|
|
16
|
+
collection.concat(includes_for(:javascript, plugin))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def stylesheet_includes
|
21
|
+
each_with_object([]) do |plugin, collection|
|
22
|
+
collection.concat(includes_for(:stylesheet, plugin))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def includes_for(type, plugin)
|
29
|
+
mod = Para::Plugins.module_name_for(plugin).constantize
|
30
|
+
mod.try(:config).try(:"#{ type }_includes") || []
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/para/plugins.rb
CHANGED
@@ -2,10 +2,11 @@ module Para
|
|
2
2
|
module Plugins
|
3
3
|
extend ActiveSupport::Autoload
|
4
4
|
|
5
|
-
autoload :Routes
|
6
|
-
|
7
5
|
def self.module_name_for(identifier)
|
8
6
|
['Para', identifier.to_s.camelize].join('::')
|
9
7
|
end
|
10
8
|
end
|
11
9
|
end
|
10
|
+
|
11
|
+
require 'para/plugins/set'
|
12
|
+
require 'para/plugins/routes'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Allows constraining routing to components that explicitly declares to use a
|
2
|
+
# given component to manage their resources.
|
3
|
+
#
|
4
|
+
# It's mainly used to allow users to override the default component for the
|
5
|
+
# resources of a given Crud or Form components without having to
|
6
|
+
# subclass the component and declare all the routes again
|
7
|
+
#
|
8
|
+
module Para
|
9
|
+
module Routing
|
10
|
+
class ComponentNameConstraint
|
11
|
+
attr_reader :component
|
12
|
+
|
13
|
+
def initialize(component)
|
14
|
+
@component = component.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def matches?(request)
|
18
|
+
component == request.params[:component]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|