para 0.4.0
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.md +65 -0
- data/Rakefile +21 -0
- data/app/assets/images/para/admin/bg.png +0 -0
- data/app/assets/javascripts/admin/app.coffee +1 -0
- data/app/assets/javascripts/para/admin/table.coffee +46 -0
- data/app/assets/javascripts/para/admin/theme_actions.coffee +26 -0
- data/app/assets/javascripts/para/admin/tree.coffee +53 -0
- data/app/assets/javascripts/para/admin.coffee +18 -0
- data/app/assets/javascripts/para/application.js +13 -0
- data/app/assets/javascripts/para/inputs/nested_many.coffee +57 -0
- data/app/assets/javascripts/para/lib/ajax.coffee +11 -0
- data/app/assets/stylesheets/admin/app.sass +0 -0
- data/app/assets/stylesheets/admin/theme.sass +0 -0
- data/app/assets/stylesheets/para/admin/theme/_base.sass +170 -0
- data/app/assets/stylesheets/para/admin/theme/_breadcrumb.sass +29 -0
- data/app/assets/stylesheets/para/admin/theme/_buttons.sass +24 -0
- data/app/assets/stylesheets/para/admin/theme/_checkable.sass +107 -0
- data/app/assets/stylesheets/para/admin/theme/_commonds.sass +213 -0
- data/app/assets/stylesheets/para/admin/theme/_dropdown.sass +53 -0
- data/app/assets/stylesheets/para/admin/theme/_form.sass +141 -0
- data/app/assets/stylesheets/para/admin/theme/_list.sass +138 -0
- data/app/assets/stylesheets/para/admin/theme/_navigation.sass +287 -0
- data/app/assets/stylesheets/para/admin/theme/_navtabs.sass +127 -0
- data/app/assets/stylesheets/para/admin/theme/_orderable.sass +44 -0
- data/app/assets/stylesheets/para/admin/theme/_panel.sass +288 -0
- data/app/assets/stylesheets/para/admin/theme/_responsive.sass +123 -0
- data/app/assets/stylesheets/para/admin/theme/_sorting.sass +30 -0
- data/app/assets/stylesheets/para/admin/theme/_table.sass +24 -0
- data/app/assets/stylesheets/para/admin/theme/_tree.sass +74 -0
- data/app/assets/stylesheets/para/admin/theme/_variables.sass +31 -0
- data/app/assets/stylesheets/para/admin/theme.sass +22 -0
- data/app/assets/stylesheets/para/admin.sass +10 -0
- data/app/assets/stylesheets/para/application.css +15 -0
- data/app/assets/stylesheets/para/lib/_variables.scss +646 -0
- data/app/assets/stylesheets/para/overrides/datetimepicker.sass +17 -0
- data/app/assets/stylesheets/para/overrides/fuelux.sass +43 -0
- data/app/assets/stylesheets/para/overrides/jasny.bootstrap.sass +41 -0
- data/app/assets/stylesheets/para/overrides/redactor.sass +88 -0
- data/app/assets/stylesheets/para/overrides/responsive.sass +63 -0
- data/app/assets/stylesheets/para/overrides/selectize.sass +45 -0
- data/app/assets/stylesheets/para/overrides/slider.sass +13 -0
- data/app/assets/stylesheets/para/overrides/theme.sass +172 -0
- data/app/controllers/concerns/para/admin/resource_controller_concerns.rb +17 -0
- data/app/controllers/para/admin/base_controller.rb +46 -0
- data/app/controllers/para/admin/component_controller.rb +9 -0
- data/app/controllers/para/admin/crud_component_controller.rb +17 -0
- data/app/controllers/para/admin/crud_resources_controller.rb +71 -0
- data/app/controllers/para/admin/main_controller.rb +8 -0
- data/app/controllers/para/admin/resources_controller.rb +163 -0
- data/app/controllers/para/admin/settings_component_controller.rb +11 -0
- data/app/controllers/para/admin/settings_form_controller.rb +21 -0
- data/app/controllers/para/admin/singleton_resource_component_controller.rb +14 -0
- data/app/controllers/para/admin/singleton_resources_controller.rb +30 -0
- data/app/controllers/para/application_controller.rb +7 -0
- data/app/decorators/para/component/base_decorator.rb +48 -0
- data/app/decorators/para/component/crud_decorator.rb +32 -0
- data/app/decorators/para/component/settings_decorator.rb +11 -0
- data/app/decorators/para/component/singleton_resource_decorator.rb +11 -0
- data/app/decorators/para/component_section_decorator.rb +4 -0
- data/app/helpers/para/admin/base_helper.rb +57 -0
- data/app/helpers/para/admin/component_groups_helper.rb +4 -0
- data/app/helpers/para/admin/components_helper.rb +4 -0
- data/app/helpers/para/admin/resources_helper.rb +27 -0
- data/app/helpers/para/application_helper.rb +14 -0
- data/app/helpers/para/exports_helper.rb +11 -0
- data/app/helpers/para/flash_helper.rb +48 -0
- data/app/helpers/para/form_helper.rb +28 -0
- data/app/helpers/para/markup_helper.rb +15 -0
- data/app/helpers/para/model_helper.rb +38 -0
- data/app/helpers/para/navigation_helper.rb +8 -0
- data/app/helpers/para/ordering_helper.rb +20 -0
- data/app/helpers/para/search_helper.rb +22 -0
- data/app/helpers/para/tag_helper.rb +50 -0
- data/app/helpers/para/tree_helper.rb +41 -0
- data/app/models/para/component/base.rb +70 -0
- data/app/models/para/component/crud.rb +45 -0
- data/app/models/para/component/resource.rb +33 -0
- data/app/models/para/component/settings.rb +17 -0
- data/app/models/para/component/singleton_resource.rb +25 -0
- data/app/models/para/component_resource.rb +6 -0
- data/app/models/para/component_section.rb +18 -0
- data/app/views/layouts/para/admin.html.haml +32 -0
- data/app/views/layouts/para/application.html.erb +14 -0
- data/app/views/para/admin/component_sections/_form.html.haml +10 -0
- data/app/views/para/admin/component_sections/edit.html.haml +5 -0
- data/app/views/para/admin/component_sections/new.html.haml +5 -0
- data/app/views/para/admin/components/_form.html.haml +15 -0
- data/app/views/para/admin/components/new.html.haml +4 -0
- data/app/views/para/admin/crud_component/show.html.haml +4 -0
- data/app/views/para/admin/dashboard.html.haml +10 -0
- data/app/views/para/admin/main/index.html.haml +1 -0
- data/app/views/para/admin/resources/_exports_menu.html.haml +12 -0
- data/app/views/para/admin/resources/_fields.html.haml +5 -0
- data/app/views/para/admin/resources/_filters.html.haml +9 -0
- data/app/views/para/admin/resources/_form.html.haml +6 -0
- data/app/views/para/admin/resources/_list.html.haml +22 -0
- data/app/views/para/admin/resources/_table.html.haml +8 -0
- data/app/views/para/admin/resources/_tree.html.haml +15 -0
- data/app/views/para/admin/resources/_tree_item.html.haml +16 -0
- data/app/views/para/admin/resources/edit.html.haml +6 -0
- data/app/views/para/admin/resources/new.html.haml +6 -0
- data/app/views/para/admin/settings_component/show.html.haml +12 -0
- data/app/views/para/admin/shared/_breadcrumb.html.haml +3 -0
- data/app/views/para/admin/shared/_header.html.haml +27 -0
- data/app/views/para/admin/shared/_navigation.html.haml +21 -0
- data/app/views/para/admin/singleton_resource_component/show.html.haml +5 -0
- data/app/views/para/inputs/_nested_many.html.haml +10 -0
- data/app/views/para/inputs/_nested_many_container.html.haml +19 -0
- data/app/views/para/inputs/_nested_one.html.haml +3 -0
- data/config/locales/en.yml +86 -0
- data/config/locales/fr.yml +101 -0
- data/db/migrate/20140911091225_create_para_components.rb +19 -0
- data/db/migrate/20140911112150_add_slug_to_para_components.rb +6 -0
- data/db/migrate/20140929125733_create_para_component_sections.rb +8 -0
- data/db/migrate/20140929131111_add_identifier_to_para_component_sections.rb +5 -0
- data/db/migrate/20140930121822_add_position_to_para_component_section.rb +5 -0
- data/db/migrate/20150129170710_create_para_component_resources.rb +13 -0
- data/db/migrate/20150203173219_add_identifier_to_para_components.rb +5 -0
- data/lib/generators/para/admin_user/admin_user_generator.rb +16 -0
- data/lib/generators/para/component/component_generator.rb +59 -0
- data/lib/generators/para/component/templates/component.rb +3 -0
- data/lib/generators/para/component/templates/component_controller.rb +7 -0
- data/lib/generators/para/component/templates/show.html.haml +2 -0
- data/lib/generators/para/exporter/exporter_generator.rb +42 -0
- data/lib/generators/para/exporter/templates/base_exporter.rb +15 -0
- data/lib/generators/para/exporter/templates/csv_exporter.rb +13 -0
- data/lib/generators/para/form/form_generator.rb +15 -0
- data/lib/generators/para/form/templates/_form.html.haml +7 -0
- data/lib/generators/para/install/install_generator.rb +112 -0
- data/lib/generators/para/install/templates/components.rb +13 -0
- data/lib/generators/para/install/templates/initializer.rb +23 -0
- data/lib/generators/para/nested_fields/nested_fields_generator.rb +15 -0
- data/lib/generators/para/nested_fields/templates/_nested_fields.html.haml +3 -0
- data/lib/generators/para/orderable/orderable_generator.rb +53 -0
- data/lib/generators/para/orderable/templates/orderable_migration.rb +6 -0
- data/lib/generators/para/resource/resource_generator.rb +71 -0
- data/lib/generators/para/resource/templates/resource_controller.rb +5 -0
- data/lib/generators/para/table/table_generator.rb +34 -0
- data/lib/generators/para/table/templates/_table.html.haml +10 -0
- data/lib/para/attribute_field/base.rb +77 -0
- data/lib/para/attribute_field/belongs_to.rb +29 -0
- data/lib/para/attribute_field/boolean.rb +15 -0
- data/lib/para/attribute_field/datetime.rb +9 -0
- data/lib/para/attribute_field/file.rb +20 -0
- data/lib/para/attribute_field/has_many.rb +31 -0
- data/lib/para/attribute_field/image.rb +25 -0
- data/lib/para/attribute_field/nested_many.rb +26 -0
- data/lib/para/attribute_field/nested_one.rb +27 -0
- data/lib/para/attribute_field/password.rb +18 -0
- data/lib/para/attribute_field/redactor.rb +20 -0
- data/lib/para/attribute_field/relation.rb +52 -0
- data/lib/para/attribute_field/translation.rb +9 -0
- data/lib/para/attribute_field_mappings.rb +82 -0
- data/lib/para/cloneable.rb +20 -0
- data/lib/para/component/exportable.rb +25 -0
- data/lib/para/component.rb +27 -0
- data/lib/para/components_configuration.rb +156 -0
- data/lib/para/config.rb +21 -0
- data/lib/para/engine.rb +59 -0
- data/lib/para/errors.rb +15 -0
- data/lib/para/exporter/base.rb +27 -0
- data/lib/para/exporter/csv.rb +49 -0
- data/lib/para/exporter.rb +57 -0
- data/lib/para/ext/cancan.rb +26 -0
- data/lib/para/ext/paperclip.rb +67 -0
- data/lib/para/ext.rb +13 -0
- data/lib/para/form_builder/containers.rb +70 -0
- data/lib/para/form_builder/field_mappings.rb +9 -0
- data/lib/para/form_builder/nested_form.rb +80 -0
- data/lib/para/form_builder/ordering.rb +15 -0
- data/lib/para/form_builder/settings.rb +24 -0
- data/lib/para/form_builder.rb +22 -0
- data/lib/para/generators/field_helpers.rb +32 -0
- data/lib/para/generators/name_helpers.rb +9 -0
- data/lib/para/generators/named_base.rb +7 -0
- data/lib/para/generators.rb +11 -0
- data/lib/para/inputs/nested_many_input.rb +40 -0
- data/lib/para/inputs/nested_one_input.rb +24 -0
- data/lib/para/inputs.rb +11 -0
- data/lib/para/markup/alert.rb +37 -0
- data/lib/para/markup/component.rb +20 -0
- data/lib/para/markup/modal.rb +52 -0
- data/lib/para/markup/panel.rb +41 -0
- data/lib/para/markup/resources_table.rb +178 -0
- data/lib/para/markup.rb +10 -0
- data/lib/para/model_field_parsers/base.rb +20 -0
- data/lib/para/model_field_parsers/devise.rb +37 -0
- data/lib/para/model_field_parsers/globalize.rb +23 -0
- data/lib/para/model_field_parsers/orderable.rb +15 -0
- data/lib/para/model_field_parsers/paperclip.rb +51 -0
- data/lib/para/model_field_parsers/redactor.rb +19 -0
- data/lib/para/model_field_parsers/relations.rb +67 -0
- data/lib/para/model_field_parsers.rb +22 -0
- data/lib/para/orderable.rb +44 -0
- data/lib/para/routes.rb +49 -0
- data/lib/para/version.rb +3 -0
- data/lib/para.rb +65 -0
- data/lib/rails/relation_length_validator.rb +45 -0
- data/lib/rails/routing_mapper.rb +27 -0
- data/lib/tasks/para_tasks.rake +22 -0
- metadata +595 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
module Para
|
2
|
+
class OrderableGenerator < Rails::Generators::NamedBase
|
3
|
+
include Rails::Generators::Migration
|
4
|
+
|
5
|
+
source_root File.expand_path('../templates', __FILE__)
|
6
|
+
|
7
|
+
class_option :migrate, type: :boolean, default: false, :aliases => "-m"
|
8
|
+
|
9
|
+
desc 'Para orderable model updater'
|
10
|
+
|
11
|
+
def welcome
|
12
|
+
say "Making #{ class_name } model orderable ..."
|
13
|
+
end
|
14
|
+
|
15
|
+
def add_field_to_model
|
16
|
+
migration_template(
|
17
|
+
'orderable_migration.rb',
|
18
|
+
"db/migrate/add_orderable_position_to_#{ plural_file_name }.rb"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_orderable_to_model
|
23
|
+
class_definition = "class #{ class_name } < ActiveRecord::Base\n"
|
24
|
+
|
25
|
+
inject_into_file "app/models/#{ file_name }.rb", after: class_definition do
|
26
|
+
" acts_as_orderable\n"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def migrate
|
31
|
+
rake 'db:migrate' if options[:migrate]
|
32
|
+
end
|
33
|
+
|
34
|
+
def fianl_message
|
35
|
+
message = "The #{ class_name } model is now orderable.\n"
|
36
|
+
message << "* Please migrate to update your model's table\n" unless options[:migrate]
|
37
|
+
message << <<-MESSAGE
|
38
|
+
* Please add to your model resource's routes the ordering path.
|
39
|
+
e.g.: resources :#{ plural_file_name } do
|
40
|
+
collection do
|
41
|
+
patch 'order'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
MESSAGE
|
45
|
+
|
46
|
+
say(message)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.next_migration_number(dir)
|
50
|
+
Time.now.utc.strftime("%Y%m%d%H%M%S")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Para
|
2
|
+
class ResourceGenerator < Rails::Generators::NamedBase
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
|
5
|
+
argument :component_name, type: :string
|
6
|
+
argument :attributes, type: :array
|
7
|
+
|
8
|
+
class_option :migrate, type: :boolean, default: false, :aliases => "-m"
|
9
|
+
class_option :orderable, type: :boolean, default: false, :aliases => "-o"
|
10
|
+
|
11
|
+
desc 'Para resource generator'
|
12
|
+
|
13
|
+
def welcome
|
14
|
+
say 'Creating resource...'
|
15
|
+
end
|
16
|
+
|
17
|
+
def copy_resource_controller
|
18
|
+
template 'resource_controller.rb', "app/controllers/admin/#{ plural_file_name }_controller.rb"
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_resource_to_component_controller
|
22
|
+
gsub_file "app/controllers/admin/#{ component_name.singularize }_component_controller.rb", /# You can access @component here/ do
|
23
|
+
<<-RUBY
|
24
|
+
@q = @component.#{ plural_file_name }.search(params[:q])
|
25
|
+
@resources = @q.result.page(params[:page])
|
26
|
+
RUBY
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def insert_route
|
31
|
+
inject_into_file 'config/routes.rb', after: "component :#{ component_name.underscore } do" do
|
32
|
+
"\n resources :#{ plural_file_name }"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def insert_relation_to_show
|
37
|
+
append_to_file "app/views/admin/#{ component_name.underscore }_component/show.html.haml" do
|
38
|
+
"\n\n= listing_for(@resources)"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def generate_model
|
43
|
+
generate 'model',
|
44
|
+
file_name,
|
45
|
+
attributes.map { |attr|
|
46
|
+
"#{ attr.name }:#{ attr.type }"
|
47
|
+
}.insert(-1, 'component:references').join(' ')
|
48
|
+
end
|
49
|
+
|
50
|
+
def orderable
|
51
|
+
generate 'para:orderable', file_name if options[:orderable]
|
52
|
+
end
|
53
|
+
|
54
|
+
def migrate
|
55
|
+
rake 'db:migrate' if options[:migrate]
|
56
|
+
end
|
57
|
+
|
58
|
+
def insert_belongs_to_to_resource
|
59
|
+
inject_into_file "app/models/#{ file_name }.rb", after: "belongs_to :component" do
|
60
|
+
", class_name: 'Para::Component::Base'"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def insert_has_many_to_component
|
65
|
+
inject_into_file "app/components/#{ component_name.underscore }_component.rb", after: "register :#{ component_name.underscore }, self" do
|
66
|
+
"\n\n has_many :#{ plural_file_name }, class_name: '::#{ class_name }', inverse_of: :component,
|
67
|
+
foreign_key: :component_id, dependent: :destroy"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Para
|
2
|
+
class TableGenerator < Para::Generators::NamedBase
|
3
|
+
source_root File.expand_path('../templates', __FILE__)
|
4
|
+
|
5
|
+
desc 'Para resources table generator'
|
6
|
+
|
7
|
+
def generate_table
|
8
|
+
template(
|
9
|
+
"_table.html.haml",
|
10
|
+
"app/views/admin/#{ plural_namespaced_path }/_table.haml"
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def attributes
|
17
|
+
@attributes ||= begin
|
18
|
+
model =
|
19
|
+
begin
|
20
|
+
Para.const_get(class_name)
|
21
|
+
rescue
|
22
|
+
class_name.classify.constantize
|
23
|
+
end
|
24
|
+
AttributeFieldMappings.new(model).fields
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def attributes_list
|
29
|
+
@attributes_list ||= attributes.map do |field|
|
30
|
+
field.name.to_sym.inspect
|
31
|
+
end.join(', ')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
= resources_table(model: model, component: component) do |table|
|
2
|
+
= table.header do
|
3
|
+
<%- attributes.each do |field| -%>
|
4
|
+
= table.header_for(:<%= field.name %>)
|
5
|
+
<%- end -%>
|
6
|
+
|
7
|
+
= table.rows(resources) do |resource|
|
8
|
+
<%- attributes.each do |field| -%>
|
9
|
+
= table.data_for(resource, :<%= field.name %>)
|
10
|
+
<%- end -%>
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class Base
|
4
|
+
class_attribute :_field_options
|
5
|
+
|
6
|
+
attr_reader :model, :name, :type, :field_type, :field_method
|
7
|
+
|
8
|
+
def self.field_option(key, method_name, options = {})
|
9
|
+
self._field_options ||= []
|
10
|
+
|
11
|
+
self._field_options += [{
|
12
|
+
key: key,
|
13
|
+
method_name: method_name,
|
14
|
+
options: options
|
15
|
+
}]
|
16
|
+
end
|
17
|
+
|
18
|
+
field_option :as, :field_type_name
|
19
|
+
|
20
|
+
def initialize(model, options = {})
|
21
|
+
@model = model
|
22
|
+
@name = options[:name]
|
23
|
+
@type = options[:type]
|
24
|
+
@field_type = options[:field_type]
|
25
|
+
|
26
|
+
determine_name_and_field_method!
|
27
|
+
end
|
28
|
+
|
29
|
+
def determine_name_and_field_method!
|
30
|
+
name = @name
|
31
|
+
|
32
|
+
reference = model.reflect_on_all_associations.find do |association|
|
33
|
+
association.foreign_key == name
|
34
|
+
end
|
35
|
+
|
36
|
+
if reference
|
37
|
+
@name = reference.name
|
38
|
+
@field_method = :association
|
39
|
+
else
|
40
|
+
@name = name
|
41
|
+
@field_method = :input
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def value_for(instance)
|
46
|
+
instance.send(name)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Allows parsing input params before they're passed to the model, so
|
50
|
+
# it can be easy to edit them according to some field type specific
|
51
|
+
# behavior
|
52
|
+
#
|
53
|
+
def parse_input(params); end
|
54
|
+
|
55
|
+
def field_options
|
56
|
+
self.class._field_options.each_with_object({}) do |params, hash|
|
57
|
+
value = send(params[:method_name])
|
58
|
+
hash[params[:key]] = value if value != nil || params[:options][:allow_nil]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def field_name
|
63
|
+
name
|
64
|
+
end
|
65
|
+
|
66
|
+
def attribute_column_path
|
67
|
+
[name]
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def field_type_name
|
73
|
+
field_type.presence && field_type.to_sym
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class BelongsToField < RelationField
|
4
|
+
field_option :collection, :relation_options
|
5
|
+
|
6
|
+
def field_name
|
7
|
+
reflection.name
|
8
|
+
end
|
9
|
+
|
10
|
+
def value_for(instance)
|
11
|
+
if (resource = instance.send(name))
|
12
|
+
resource_name(resource)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def relation_options
|
17
|
+
reflection.klass.all
|
18
|
+
end
|
19
|
+
|
20
|
+
def parse_input(params)
|
21
|
+
if (id = params[reflection.foreign_key].presence) && !reflection.klass.exists?(id: id)
|
22
|
+
on_the_fly_creation(id) do |resource|
|
23
|
+
params[reflection.foreign_key] = resource.id
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class BooleanField < AttributeField::Base
|
4
|
+
field_option :wrapper, :wrapper_name
|
5
|
+
|
6
|
+
def value_for(instance)
|
7
|
+
I18n.t("para.types.boolean.#{ (!!instance.send(name)).to_s }")
|
8
|
+
end
|
9
|
+
|
10
|
+
def wrapper_name
|
11
|
+
:horizontal_radio_and_checkboxes
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class FileField < AttributeField::Base
|
4
|
+
include ActionView::Helpers::UrlHelper
|
5
|
+
|
6
|
+
field_option :wrapper, :wrapper_name
|
7
|
+
|
8
|
+
def value_for(instance)
|
9
|
+
if instance.send(:"#{ name }?")
|
10
|
+
url = instance.send(name).url
|
11
|
+
link_to(url, url)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def wrapper_name
|
16
|
+
:horizontal_file_input
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class HasManyField < RelationField
|
4
|
+
def field_name
|
5
|
+
reflection.name
|
6
|
+
end
|
7
|
+
|
8
|
+
def value_for(instance)
|
9
|
+
instance.send(name).map do |resource|
|
10
|
+
resource_name(resource)
|
11
|
+
end.join(', ')
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_input(params)
|
15
|
+
if (ids = params[plural_foreign_key].presence) && String === ids
|
16
|
+
# Format selectize value for Rails
|
17
|
+
ids = params[plural_foreign_key] = ids.split(',')
|
18
|
+
|
19
|
+
on_the_fly_creation(ids) do |resource, value|
|
20
|
+
params[plural_foreign_key].delete(value)
|
21
|
+
params[plural_foreign_key] << resource.id
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def plural_foreign_key
|
27
|
+
foreign_key.to_s.pluralize
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class ImageField < AttributeField::Base
|
4
|
+
include ActionView::Helpers::AssetTagHelper
|
5
|
+
|
6
|
+
def value_for(instance)
|
7
|
+
style = attachment_thumb_style_for(instance)
|
8
|
+
|
9
|
+
if instance.send(:"#{ name }?")
|
10
|
+
image_tag(instance.send(name).url(style))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def attachment_thumb_style_for(instance)
|
17
|
+
styles = instance.send(name).styles.map(&:first)
|
18
|
+
# Check if there's a :thumb or :thumbnail style in attachment definition
|
19
|
+
thumb = styles.find { |s| %w(thumb thumbnail).include?(s.to_s) }
|
20
|
+
# Return the potentially smallest size !
|
21
|
+
thumb || styles.first || :original
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class NestedManyField < AttributeField::HasManyField
|
4
|
+
def parse_input(params)
|
5
|
+
if (nested_attributes = params[nested_attributes_key])
|
6
|
+
nested_attributes.each do |index, attributes|
|
7
|
+
nested_model_mappings.fields.each do |field|
|
8
|
+
field.parse_input(attributes)
|
9
|
+
end
|
10
|
+
params[nested_attributes_key][index] = attributes
|
11
|
+
end
|
12
|
+
else
|
13
|
+
super(params)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def nested_model_mappings
|
18
|
+
@nested_model_mappings ||= AttributeFieldMappings.new(reflection.klass)
|
19
|
+
end
|
20
|
+
|
21
|
+
def nested_attributes_key
|
22
|
+
@nested_attributes_key ||= :"#{ name }_attributes"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class NestedOneField < AttributeField::BelongsToField
|
4
|
+
def parse_input(params)
|
5
|
+
if (nested_attributes = params[nested_attributes_key])
|
6
|
+
nested_attributes.each do |index, attributes|
|
7
|
+
nested_model_mappings.fields.each do |field|
|
8
|
+
field.parse_input(attributes)
|
9
|
+
end
|
10
|
+
|
11
|
+
params[nested_attributes_key][index] = attributes
|
12
|
+
end
|
13
|
+
else
|
14
|
+
super(params)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def nested_model_mappings
|
19
|
+
@nested_model_mappings ||= AttributeFieldMappings.new(reflection.klass)
|
20
|
+
end
|
21
|
+
|
22
|
+
def nested_attributes_key
|
23
|
+
@nested_attributes_key ||= :"#{ name }_attributes"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class PasswordField < AttributeField::Base
|
4
|
+
def initialize(model, options = {})
|
5
|
+
options.reverse_merge!(type: 'password', field_type: 'password')
|
6
|
+
super(model, options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def value_for(instance)
|
10
|
+
nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse_input(params)
|
14
|
+
params[name] = params[name].presence
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class Redactor < AttributeField::Base
|
4
|
+
include ActionView::Helpers::SanitizeHelper
|
5
|
+
include ActionView::Helpers::TextHelper
|
6
|
+
|
7
|
+
def initialize(model, options = {})
|
8
|
+
options.reverse_merge!(type: 'text', field_type: 'redactor')
|
9
|
+
super(model, options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def value_for(instance)
|
13
|
+
(value = instance.send(name)) && truncate(
|
14
|
+
sanitize(value, tags: []),
|
15
|
+
length: 50
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Para
|
2
|
+
module AttributeField
|
3
|
+
class RelationField < AttributeField::Base
|
4
|
+
private
|
5
|
+
|
6
|
+
def reflection
|
7
|
+
@reflection ||= model.reflect_on_association(name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def foreign_key
|
11
|
+
@foreign_key ||= reflection && case reflection.macro
|
12
|
+
when :belongs_to then reflection.foreign_key
|
13
|
+
when :has_one then :"#{ reflection.name }_id"
|
14
|
+
when :has_many then :"#{ reflection.name.to_s.singularize }_ids"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def resource_name(resource)
|
19
|
+
Para.config.resource_name_methods.each do |method|
|
20
|
+
return resource.send(method) if resource.respond_to?(method)
|
21
|
+
end
|
22
|
+
|
23
|
+
model_name = resource.class.model_name.human
|
24
|
+
"#{ model_name } - #{ resource.id }"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Takes an array of ids and a block. Check for each id if model exists
|
28
|
+
# and create one if not. E.g: [12, "foo"] will try to create a model with
|
29
|
+
# 'foo'
|
30
|
+
def on_the_fly_creation ids, &block
|
31
|
+
Array.wrap(ids).each do |id|
|
32
|
+
if !reflection.klass.exists?(id: id)
|
33
|
+
resource = reflection.klass.new
|
34
|
+
|
35
|
+
Para.config.resource_name_methods.each do |method_name|
|
36
|
+
setter_name = :"#{ method_name }="
|
37
|
+
|
38
|
+
if resource.respond_to?(setter_name)
|
39
|
+
resource.send(setter_name, id)
|
40
|
+
|
41
|
+
if resource.save
|
42
|
+
block.call(resource, id)
|
43
|
+
break
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'para/attribute_field/base'
|
2
|
+
require 'para/attribute_field/boolean'
|
3
|
+
require 'para/attribute_field/datetime'
|
4
|
+
require 'para/attribute_field/password'
|
5
|
+
require 'para/attribute_field/file'
|
6
|
+
require 'para/attribute_field/image'
|
7
|
+
require 'para/attribute_field/relation'
|
8
|
+
require 'para/attribute_field/belongs_to'
|
9
|
+
require 'para/attribute_field/has_many'
|
10
|
+
require 'para/attribute_field/nested_one'
|
11
|
+
require 'para/attribute_field/nested_many'
|
12
|
+
require 'para/attribute_field/redactor'
|
13
|
+
require 'para/attribute_field/translation'
|
14
|
+
|
15
|
+
module Para
|
16
|
+
class AttributeFieldMappings
|
17
|
+
UNEDITABLE_ATTRIBUTES = %w(id component_id created_at updated_at type)
|
18
|
+
|
19
|
+
attr_reader :model, :fields_hash, :whitelist_attributes
|
20
|
+
|
21
|
+
def initialize(model, whitelist_attributes: nil)
|
22
|
+
@model = model
|
23
|
+
@whitelist_attributes = whitelist_attributes
|
24
|
+
|
25
|
+
process_fields!
|
26
|
+
end
|
27
|
+
|
28
|
+
def fields
|
29
|
+
fields_hash.values
|
30
|
+
end
|
31
|
+
|
32
|
+
def field_for(field_name, type = nil)
|
33
|
+
fields_hash[field_name] ||= if model.new.respond_to?(field_name)
|
34
|
+
build_field_for(field_name, type)
|
35
|
+
else
|
36
|
+
raise NoMethodError.new(
|
37
|
+
"No attribute or method correspond to ##{ field_name } " +
|
38
|
+
"in the model #{ model.name }. No field could be created."
|
39
|
+
)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def whitelisted?(attribute_name)
|
46
|
+
!whitelist_attributes || whitelist_attributes.include?(attribute_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def process_fields!
|
50
|
+
@fields_hash = model.columns.each_with_object({}) do |column, fields|
|
51
|
+
next unless whitelisted?(column.name)
|
52
|
+
|
53
|
+
# Reject uneditable attributes
|
54
|
+
unless UNEDITABLE_ATTRIBUTES.include?(column.name)
|
55
|
+
field_class = field_class_for(column.type)
|
56
|
+
|
57
|
+
fields[column.name] = field_class.new(
|
58
|
+
model, name: column.name, type: column.type
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end.with_indifferent_access
|
62
|
+
|
63
|
+
Para::ModelFieldParsers.parse!(model, fields_hash)
|
64
|
+
end
|
65
|
+
|
66
|
+
def build_field_for(attribute_name, type)
|
67
|
+
field_class = field_class_for(type)
|
68
|
+
|
69
|
+
field_class.new(
|
70
|
+
model, name: attribute_name, type: type
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def field_class_for(type)
|
75
|
+
case type
|
76
|
+
when :boolean then AttributeField::BooleanField
|
77
|
+
when :date, :datetime then AttributeField::DatetimeField
|
78
|
+
else AttributeField::Base
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Para
|
2
|
+
module Cloneable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :cloneable_associations
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def acts_as_cloneable(*args)
|
11
|
+
@cloneable = true
|
12
|
+
self.cloneable_associations = args
|
13
|
+
end
|
14
|
+
|
15
|
+
def cloneable?
|
16
|
+
@cloneable ||= false
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Para
|
2
|
+
module Component
|
3
|
+
module Exportable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
configurable_on :export
|
8
|
+
end
|
9
|
+
|
10
|
+
def exportable?
|
11
|
+
@exportable ||= exports.length > 0
|
12
|
+
end
|
13
|
+
|
14
|
+
# TODO : Move :configuration column store to JSON instead of HStore
|
15
|
+
# which handles more data types and will help us avoid eval here
|
16
|
+
def exports
|
17
|
+
@exports ||= if export.present?
|
18
|
+
eval(export).map(&:with_indifferent_access)
|
19
|
+
else
|
20
|
+
[]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|