para 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.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,24 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module FormBuilder
|
|
3
|
+
module Settings
|
|
4
|
+
def settings_input(name, options = {}, &block)
|
|
5
|
+
options.reverse_merge!(as: :setting)
|
|
6
|
+
|
|
7
|
+
setting = ::Settings.get(name, options[:type])
|
|
8
|
+
|
|
9
|
+
input(name, options) do
|
|
10
|
+
fields_for(:settings, setting) do |fields|
|
|
11
|
+
fields.hidden_field(:key) +
|
|
12
|
+
fields.hidden_field(:_type) +
|
|
13
|
+
|
|
14
|
+
if block
|
|
15
|
+
block.call(fields)
|
|
16
|
+
else
|
|
17
|
+
fields.text_field(:value, class: 'form-control')
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require 'simple_form/form_builder'
|
|
2
|
+
|
|
3
|
+
require 'para/form_builder/containers'
|
|
4
|
+
require 'para/form_builder/field_mappings'
|
|
5
|
+
require 'para/form_builder/nested_form'
|
|
6
|
+
require 'para/form_builder/ordering'
|
|
7
|
+
require 'para/form_builder/settings'
|
|
8
|
+
|
|
9
|
+
# We'll implement our own form builder later, but for now it would need to
|
|
10
|
+
# patch or override Cocoon to allow creating nested fields with our custom
|
|
11
|
+
# form builder instead of `simple_fields_for` which uses SimpleForm::FormBuilder
|
|
12
|
+
# explicitly
|
|
13
|
+
#
|
|
14
|
+
SimpleForm::FormBuilder.class_eval do
|
|
15
|
+
include Para::FormBuilder::Containers
|
|
16
|
+
include Para::FormBuilder::FieldMappings
|
|
17
|
+
include Para::FormBuilder::NestedForm
|
|
18
|
+
include Para::FormBuilder::Ordering
|
|
19
|
+
include Para::FormBuilder::Settings
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
SimpleForm::FormBuilder.map_type(:inet, to: SimpleForm::Inputs::StringInput)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Generators
|
|
3
|
+
module FieldHelpers
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def attributes
|
|
7
|
+
@attributes ||= begin
|
|
8
|
+
model = Para.const_get(class_name)
|
|
9
|
+
AttributeFieldMappings.new(model).fields
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def field_options_for(field)
|
|
14
|
+
field_options = field.field_options
|
|
15
|
+
|
|
16
|
+
options = field_options.each_with_object([]) do |(key, value), ary|
|
|
17
|
+
if writable_value?(value)
|
|
18
|
+
ary << "#{ key.inspect } => #{ value.inspect }"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
", #{ options.join(', ') }" if options.any?
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def writable_value?(value)
|
|
26
|
+
[String, Symbol].any? do |type|
|
|
27
|
+
value.kind_of?(type)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Inputs
|
|
3
|
+
class NestedManyInput < SimpleForm::Inputs::Base
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
|
+
input_html_options[:class] << "nested-many"
|
|
6
|
+
|
|
7
|
+
parent_model = @builder.object.class
|
|
8
|
+
model = parent_model.reflect_on_association(attribute_name).klass
|
|
9
|
+
orderable = options.fetch(:orderable, model.orderable?)
|
|
10
|
+
add_button = options.fetch(:add_button, true)
|
|
11
|
+
# Load existing resources
|
|
12
|
+
resources = object.send(attribute_name)
|
|
13
|
+
# Order them if the list should be orderable
|
|
14
|
+
resources = resources.order(:position) if orderable
|
|
15
|
+
|
|
16
|
+
template.render(
|
|
17
|
+
partial: 'para/inputs/nested_many',
|
|
18
|
+
locals: {
|
|
19
|
+
form: @builder,
|
|
20
|
+
model: model,
|
|
21
|
+
attribute_name: attribute_name,
|
|
22
|
+
orderable: orderable,
|
|
23
|
+
add_button: add_button,
|
|
24
|
+
dom_identifier: dom_identifier,
|
|
25
|
+
resources: resources
|
|
26
|
+
}
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def dom_identifier
|
|
31
|
+
@dom_identifier ||= begin
|
|
32
|
+
name = attribute_name
|
|
33
|
+
time = (Time.now.to_f * 1000).to_i
|
|
34
|
+
random = (rand * 1000).to_i
|
|
35
|
+
[name, time, random].join('-')
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Inputs
|
|
3
|
+
class NestedOneInput < SimpleForm::Inputs::Base
|
|
4
|
+
def input(wrapper_options = nil)
|
|
5
|
+
input_html_options[:class] << "nested-one"
|
|
6
|
+
|
|
7
|
+
parent_model = object.class
|
|
8
|
+
model = parent_model.reflect_on_association(attribute_name).klass
|
|
9
|
+
resource = object.send(:"#{ attribute_name }") ||
|
|
10
|
+
object.send(:"#{ attribute_name }=", model.new)
|
|
11
|
+
|
|
12
|
+
template.render(
|
|
13
|
+
partial: 'para/inputs/nested_one',
|
|
14
|
+
locals: {
|
|
15
|
+
form: @builder,
|
|
16
|
+
model: model,
|
|
17
|
+
resource: resource,
|
|
18
|
+
attribute_name: attribute_name
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
data/lib/para/inputs.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Markup
|
|
3
|
+
class Alert < Para::Markup::Component
|
|
4
|
+
def container(message, options = {}, &block)
|
|
5
|
+
if block
|
|
6
|
+
options = message
|
|
7
|
+
message = capture { block.call }
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
type = options.delete(:type) || 'info'
|
|
11
|
+
|
|
12
|
+
merge_class!(options, "alert")
|
|
13
|
+
merge_class!(options, "alert-#{ type }")
|
|
14
|
+
|
|
15
|
+
dismissable = !options.key?(:dismissable) || options.delete(:dismissable)
|
|
16
|
+
|
|
17
|
+
merge_class!(options, "alert-dismissable") if dismissable
|
|
18
|
+
|
|
19
|
+
content_tag :div, options do
|
|
20
|
+
if dismissable
|
|
21
|
+
close_button + message
|
|
22
|
+
else
|
|
23
|
+
message
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def close_button
|
|
31
|
+
content_tag(:button, type: "button", class: "close", "data-dismiss" => "alert") do
|
|
32
|
+
content_tag(:span, '×'.html_safe)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Markup
|
|
3
|
+
class Component
|
|
4
|
+
attr_reader :view
|
|
5
|
+
|
|
6
|
+
delegate :content_tag, :capture, to: :view
|
|
7
|
+
|
|
8
|
+
def initialize view
|
|
9
|
+
@view = view
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
protected
|
|
13
|
+
|
|
14
|
+
def merge_class!(options, klass)
|
|
15
|
+
options[:class] ||= ""
|
|
16
|
+
options[:class] += " #{ klass }"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Markup
|
|
3
|
+
class Modal < Para::Markup::Component
|
|
4
|
+
def container(options = {}, &block)
|
|
5
|
+
merge_class!(options, "modal")
|
|
6
|
+
merge_class!(options, "fade") unless options.delete(:fade) == false
|
|
7
|
+
merge_class!(options, "in") if options.delete(:displayed)
|
|
8
|
+
|
|
9
|
+
options.reverse_merge!(
|
|
10
|
+
tabindex: "-1", role: "dialog", "aria-hidden" => "true", "aria-labelledby" => (options[:id] || "modal")
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
content_tag(:div, options) do
|
|
14
|
+
content_tag(:div, class: "modal-dialog") do
|
|
15
|
+
content_tag(:div, class: "modal-content") do
|
|
16
|
+
capture { block.call(self) }
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def header(options = {}, &block)
|
|
23
|
+
merge_class!(options, "modal-header")
|
|
24
|
+
|
|
25
|
+
content_tag(:div, options) do
|
|
26
|
+
content_tag(:button, "×".html_safe, class: "close", type: "button",
|
|
27
|
+
"data-dismiss" => "modal", "aria-hidden" => "true"
|
|
28
|
+
) +
|
|
29
|
+
content_tag(:h4, class: "modal-title") do
|
|
30
|
+
capture { block.call }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def body(options = {}, &block)
|
|
36
|
+
merge_class!(options, "modal-body")
|
|
37
|
+
|
|
38
|
+
content_tag(:div, options) do
|
|
39
|
+
capture { block.call }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def footer(options = {}, &block)
|
|
44
|
+
merge_class!(options, "modal-footer")
|
|
45
|
+
|
|
46
|
+
content_tag(:div, options) do
|
|
47
|
+
capture { block.call }
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Markup
|
|
3
|
+
class Panel < Para::Markup::Component
|
|
4
|
+
def container(options = {}, &block)
|
|
5
|
+
merge_class!(options, "panel")
|
|
6
|
+
|
|
7
|
+
if (type = options.fetch(:type, 'default'))
|
|
8
|
+
merge_class!(options, "panel-#{ type }")
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
content_tag(:div, options) do
|
|
12
|
+
capture { block.call(self) }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def header(options = {}, &block)
|
|
17
|
+
merge_class!(options, "panel-heading")
|
|
18
|
+
|
|
19
|
+
content_tag(:div, options) do
|
|
20
|
+
capture { block.call }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def body(options = {}, &block)
|
|
25
|
+
merge_class!(options, "panel-body")
|
|
26
|
+
|
|
27
|
+
content_tag(:div, options) do
|
|
28
|
+
capture { block.call }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def footer(options = {}, &block)
|
|
33
|
+
merge_class!(options, "panel-footer")
|
|
34
|
+
|
|
35
|
+
content_tag(:div, options) do
|
|
36
|
+
capture { block.call }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module Markup
|
|
3
|
+
class ResourcesTable < Para::Markup::Component
|
|
4
|
+
attr_reader :model, :component, :orderable, :actions
|
|
5
|
+
|
|
6
|
+
def container(options = {}, &block)
|
|
7
|
+
@model = options.delete(:model)
|
|
8
|
+
@component = options.delete(:component)
|
|
9
|
+
|
|
10
|
+
if !options.key?(:orderable) || options.delete(:orderable)
|
|
11
|
+
@orderable = model.orderable?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
if !options.key?(:actions) || options.delete(:actions)
|
|
15
|
+
@actions = true
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
merge_class!(options, 'table')
|
|
19
|
+
merge_class!(options, 'para-component-relation-table')
|
|
20
|
+
merge_class!(options, 'table-hover') if options.fetch(:hover, true)
|
|
21
|
+
|
|
22
|
+
if orderable
|
|
23
|
+
merge_class!(options, 'orderable')
|
|
24
|
+
options[:data] ||= {}
|
|
25
|
+
options[:data][:'order-url'] = component.relation_path(model.model_name.route_key, action: :order)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
table = content_tag(:table, options) do
|
|
29
|
+
capture { block.call(self) }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
if options.fetch(:responsive, true)
|
|
33
|
+
content_tag(:div, table, class: 'table-responsive')
|
|
34
|
+
else
|
|
35
|
+
table
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def header(&block)
|
|
40
|
+
cells = []
|
|
41
|
+
# Add orderable empty header
|
|
42
|
+
cells << content_tag(:th, '') if orderable
|
|
43
|
+
# Append cells
|
|
44
|
+
cells << capture { block.call }
|
|
45
|
+
# Append actions empty cell
|
|
46
|
+
cells << content_tag(:th, '', class: 'actions') if actions
|
|
47
|
+
|
|
48
|
+
# Output full header
|
|
49
|
+
content_tag(:thead) do
|
|
50
|
+
content_tag(:tr, cells.join("\n").html_safe)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def rows(resources, &block)
|
|
55
|
+
rows = resources.each_with_object(ActiveSupport::SafeBuffer.new('')) do |resource, buffer|
|
|
56
|
+
buffer << content_tag(:tr, row(resource, &block))
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Output full header
|
|
60
|
+
content_tag(:tbody, rows)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def row(resource, &block)
|
|
64
|
+
cells = []
|
|
65
|
+
# Add orderable cell with "move" thumb
|
|
66
|
+
cells << order_cell(resource) if orderable
|
|
67
|
+
# Add data cells
|
|
68
|
+
cells << capture { block.call(resource) }
|
|
69
|
+
# Add actions links to the last cell
|
|
70
|
+
cells << actions_cell(resource) if actions
|
|
71
|
+
|
|
72
|
+
cells.join("\n").html_safe
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def header_for(field_name, sort: field_name)
|
|
76
|
+
label = model.human_attribute_name(field_name)
|
|
77
|
+
|
|
78
|
+
content_tag(:th) do
|
|
79
|
+
if sort != field_name
|
|
80
|
+
view.sort_link(search, *sort, label, hide_indicator: true)
|
|
81
|
+
elsif searchable?(field_name)
|
|
82
|
+
view.sort_link(search, field_name, label, hide_indicator: true)
|
|
83
|
+
else
|
|
84
|
+
label
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Data for can accept 2 versions of arguments :
|
|
90
|
+
#
|
|
91
|
+
# - resource, field_name, type : cell value will be retrieved from
|
|
92
|
+
# the field_value_for helper
|
|
93
|
+
#
|
|
94
|
+
# - a single value : The value to display in the cell directly
|
|
95
|
+
# which will be processed to be shorter than 100 chars
|
|
96
|
+
#
|
|
97
|
+
def data_for(*args)
|
|
98
|
+
value = if args.length >= 2
|
|
99
|
+
resource, field_name, type = args
|
|
100
|
+
view.field_value_for(resource, field_name, type).to_s
|
|
101
|
+
else
|
|
102
|
+
view.excerpt_value_for(args.first)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
content_tag(:td) do
|
|
106
|
+
value
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def order_cell(resource)
|
|
111
|
+
order_cell = content_tag(:td) do
|
|
112
|
+
view.reorder_anchor(
|
|
113
|
+
value: resource.position,
|
|
114
|
+
data: { id: resource.id }
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def actions_cell(resource)
|
|
120
|
+
content_tag(:td) do
|
|
121
|
+
content_tag(:div, class: 'pull-right btn-group') do
|
|
122
|
+
edit_button(resource) +
|
|
123
|
+
clone_button(resource) +
|
|
124
|
+
delete_button(resource)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def clone_button(resource)
|
|
130
|
+
return unless resource.class.cloneable?
|
|
131
|
+
|
|
132
|
+
view.link_to(
|
|
133
|
+
component.relation_path(
|
|
134
|
+
resource, action: :clone, return_to: view.request.fullpath
|
|
135
|
+
),
|
|
136
|
+
method: :post,
|
|
137
|
+
class: 'btn btn-info'
|
|
138
|
+
) do
|
|
139
|
+
content_tag(:i, '', class: 'fa fa-refresh')
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def edit_button(resource)
|
|
144
|
+
view.link_to(
|
|
145
|
+
component.relation_path(
|
|
146
|
+
resource, action: :edit, return_to: view.request.fullpath
|
|
147
|
+
),
|
|
148
|
+
class: 'btn btn-primary'
|
|
149
|
+
) do
|
|
150
|
+
content_tag(:i, '', class: 'fa fa-pencil')
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def delete_button(resource)
|
|
155
|
+
view.link_to(
|
|
156
|
+
component.relation_path(resource),
|
|
157
|
+
method: :delete,
|
|
158
|
+
data: {
|
|
159
|
+
confirm: I18n.t('para.list.delete_confirmation')
|
|
160
|
+
},
|
|
161
|
+
class: 'btn btn-danger'
|
|
162
|
+
) do
|
|
163
|
+
content_tag(:i, '', class: 'fa fa-trash')
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
private
|
|
168
|
+
|
|
169
|
+
def search
|
|
170
|
+
@search ||= view.instance_variable_get(:@q)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def searchable?(field_name)
|
|
174
|
+
model.columns_hash.keys.include?(field_name.to_s)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
data/lib/para/markup.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module ModelFieldParsers
|
|
3
|
+
class Base
|
|
4
|
+
def self.register(key, parser)
|
|
5
|
+
ModelFieldParsers.registered_parsers[key] = parser
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
attr_reader :model, :fields_hash
|
|
9
|
+
|
|
10
|
+
def initialize(model, fields_hash)
|
|
11
|
+
@model = model
|
|
12
|
+
@fields_hash = fields_hash
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def applicable?
|
|
16
|
+
true
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module ModelFieldParsers
|
|
3
|
+
class Devise < Para::ModelFieldParsers::Base
|
|
4
|
+
register :devise, self
|
|
5
|
+
|
|
6
|
+
def parse!
|
|
7
|
+
hidden_fields.each(&fields_hash.method(:delete))
|
|
8
|
+
|
|
9
|
+
added_fields.each do |key|
|
|
10
|
+
fields_hash[key] = AttributeField::PasswordField.new(model, name: key)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def applicable?
|
|
15
|
+
fields_hash.key?(:encrypted_password)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def hidden_fields
|
|
21
|
+
[
|
|
22
|
+
:encrypted_password,
|
|
23
|
+
:password_salt,
|
|
24
|
+
:reset_password_token,
|
|
25
|
+
:remember_token
|
|
26
|
+
]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def added_fields
|
|
30
|
+
[
|
|
31
|
+
:password,
|
|
32
|
+
:password_confirmation
|
|
33
|
+
]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module ModelFieldParsers
|
|
3
|
+
class Globalize < Para::ModelFieldParsers::Base
|
|
4
|
+
register :globalize, self
|
|
5
|
+
|
|
6
|
+
def parse!
|
|
7
|
+
fields_hash.delete(:translations)
|
|
8
|
+
|
|
9
|
+
model.translated_attribute_names.each do |attribute_name|
|
|
10
|
+
column = model.translation_class.columns_hash[attribute_name.to_s]
|
|
11
|
+
|
|
12
|
+
fields_hash[column.name] = AttributeField::Translation.new(
|
|
13
|
+
model, name: column.name, type: column.type
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def applicable?
|
|
19
|
+
defined?(::Globalize) && model.translates?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module Para
|
|
2
|
+
module ModelFieldParsers
|
|
3
|
+
class Paperclip < Para::ModelFieldParsers::Base
|
|
4
|
+
register :paperclip, self
|
|
5
|
+
|
|
6
|
+
def parse!
|
|
7
|
+
model.attachment_definitions.each do |key, options|
|
|
8
|
+
paperclip_suffixes.each do |suffix|
|
|
9
|
+
field_name = [key, suffix].join('_').to_sym
|
|
10
|
+
@fields_hash.delete(field_name)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
@fields_hash[key] = if image?(options)
|
|
14
|
+
AttributeField::ImageField.new(
|
|
15
|
+
model, name: key, type: 'image', field_type: 'image'
|
|
16
|
+
)
|
|
17
|
+
else
|
|
18
|
+
AttributeField::FileField.new(
|
|
19
|
+
model, name: key, type: 'file', field_type: 'file'
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def applicable?
|
|
26
|
+
model.respond_to?(:attachment_definitions)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def paperclip_suffixes
|
|
32
|
+
[
|
|
33
|
+
:file_name,
|
|
34
|
+
:content_type,
|
|
35
|
+
:file_size,
|
|
36
|
+
:updated_at
|
|
37
|
+
]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# For our default, we tell that an attachment is an image if it
|
|
41
|
+
# has at least one style and that this style starts with a digit or the
|
|
42
|
+
# "x" letter, which is used for styles like "x200" to only force height
|
|
43
|
+
#
|
|
44
|
+
def image?(options)
|
|
45
|
+
if (styles = options[:styles]) && !styles.empty?
|
|
46
|
+
styles.values.first.match(/^(\d|x)/i)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|