para 0.6.3 → 0.6.7
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 +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
|