para 0.5.1 → 0.5.3

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/para/inputs/nested_many.coffee +2 -1
  3. data/app/assets/stylesheets/para/admin/src/page-top-bar.sass +9 -0
  4. data/app/assets/stylesheets/para/admin/theme/_base.sass +1 -0
  5. data/app/controllers/para/admin/crud_resources_controller.rb +7 -1
  6. data/app/controllers/para/admin/settings_component_controller.rb +14 -0
  7. data/app/decorators/para/component/crud_decorator.rb +8 -4
  8. data/app/helpers/para/admin/base_helper.rb +5 -3
  9. data/app/helpers/para/admin/page_helper.rb +32 -0
  10. data/app/helpers/para/tree_helper.rb +2 -2
  11. data/app/models/para/component/base.rb +1 -1
  12. data/app/models/para/component_section.rb +1 -1
  13. data/app/models/para/page/section.rb +21 -0
  14. data/app/views/layouts/para/admin.html.haml +2 -2
  15. data/app/views/para/admin/crud_resources/index.html.haml +1 -2
  16. data/app/views/para/admin/dashboard.html.haml +1 -2
  17. data/app/views/para/admin/resources/_table.html.haml +2 -2
  18. data/app/views/para/admin/resources/_tree_item.html.haml +7 -4
  19. data/app/views/para/admin/resources/edit.html.haml +1 -3
  20. data/app/views/para/admin/resources/new.html.haml +1 -3
  21. data/app/views/para/admin/settings_component/show.html.haml +2 -3
  22. data/app/views/para/admin/singleton_resources/show.html.haml +1 -2
  23. data/app/views/para/inputs/_nested_many.html.haml +1 -2
  24. data/app/views/para/inputs/nested_many/_container.html.haml +2 -1
  25. data/db/migrate/20160419145254_create_para_page_sections.rb +12 -0
  26. data/lib/generators/para/component/templates/show.html.haml +1 -2
  27. data/lib/generators/para/install/templates/initializer.rb +5 -1
  28. data/lib/generators/para/nested_fields/nested_fields_generator.rb +2 -2
  29. data/lib/generators/para/page/section/section_generator.rb +28 -0
  30. data/lib/generators/para/page/section/templates/section.rb.erb +6 -0
  31. data/lib/para/attribute_field/boolean.rb +1 -1
  32. data/lib/para/attribute_field/enum.rb +1 -1
  33. data/lib/para/breadcrumbs/breadcrumb.rb +1 -1
  34. data/lib/para/config.rb +21 -2
  35. data/lib/para/engine.rb +12 -0
  36. data/lib/para/ext/simple_form_extension.rb +21 -0
  37. data/lib/para/ext.rb +1 -0
  38. data/lib/para/form_builder/containers.rb +4 -4
  39. data/lib/para/form_builder/nested_form.rb +2 -2
  40. data/lib/para/form_builder/tabs.rb +1 -1
  41. data/lib/para/generators/field_helpers.rb +10 -3
  42. data/lib/para/inputs/nested_many_input.rb +2 -0
  43. data/lib/para/markup/resources_table.rb +15 -10
  44. data/lib/para/model_field_parsers/store.rb +24 -1
  45. data/lib/para/page/model.rb +12 -0
  46. data/lib/para/page.rb +6 -0
  47. data/lib/para/routes.rb +13 -0
  48. data/lib/para/sti/root_model.rb +58 -0
  49. data/lib/para/sti.rb +6 -0
  50. data/lib/para/version.rb +1 -1
  51. data/lib/para.rb +3 -0
  52. data/lib/rails/relation_length_validator.rb +2 -2
  53. data/lib/rails/routing_mapper.rb +13 -1
  54. metadata +27 -4
  55. data/app/controllers/para/admin/settings_form_controller.rb +0 -21
  56. data/app/views/para/admin/crud_component/show.html.haml +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 732caede63e764554d7a140b937d9b2c22ca9c85
4
- data.tar.gz: 2cf5c7b7351487eb7b6c73de119fe8e0b17a79af
3
+ metadata.gz: 855b5d4493847325b66af2955504dcb8524f9e2d
4
+ data.tar.gz: 32e9da832c3641f4993cdd3c65096782ef4ba14b
5
5
  SHA512:
6
- metadata.gz: abf828d53004049d831e19fb4125cc5ab54c254decc1f28a30a06bf8866f5bae76ca287d2e2b5664a28685c278106bd9ce269c51c1f6822be0984beab3a47148
7
- data.tar.gz: c271d48d9883fd0f5268efddddf48efa61a3b77cc8ca4309896aeb8ec3c18f17f60a59522d746e04b94b34fb84c7fc1683b6147bc24fec5780015197796a88b0
6
+ metadata.gz: b5f34e153a1bc38d5e07e37c96b7a9f181e0be8957d1c1d685d3606649fcfefd88a426e8fd201302289f81d99ba076919e98295c8ae8c720cf3aed61698846db
7
+ data.tar.gz: 790dffa7b7fa6d327548b23e3a1dec0aeabf115bea3ceb6aa4fd31588f4c5f0318f1b23ca4daf3da6167e2bbde207bdcd1cdc4a5358443d23fcdc686bba1d86c
@@ -17,7 +17,7 @@ class Para.NestedManyField
17
17
 
18
18
  @$fieldsList.on('sortupdate', $.proxy(@sortUpdate, this))
19
19
 
20
- sortUpdate: (e, ui) ->
20
+ sortUpdate: ->
21
21
  @$fieldsList.find('.form-fields').each (i, el) ->
22
22
  $(el).find('.resource-position-field').val(i)
23
23
 
@@ -31,6 +31,7 @@ class Para.NestedManyField
31
31
  if @orderable
32
32
  @$fieldsList.sortable('destroy')
33
33
  @initializeOrderable()
34
+ @sortUpdate()
34
35
 
35
36
  if ($redactor = $element.find('[data-redactor]')).length
36
37
  $redactor.simpleFormRedactor()
@@ -0,0 +1,9 @@
1
+ .page-actions
2
+ float: left
3
+ padding:
4
+ left: 10px
5
+ margin:
6
+ top: 15px
7
+ left: 10px
8
+ border:
9
+ left: 1px solid #ccc
@@ -13,6 +13,7 @@ body, html
13
13
  -moz-osx-font-smoothing: grayscale
14
14
 
15
15
  .body-full-height
16
+ height: 100%
16
17
  body
17
18
  height: 100%
18
19
 
@@ -95,7 +95,7 @@ module Para
95
95
  end
96
96
 
97
97
  def add_breadcrumbs
98
- add_breadcrumb(resource_title_for(resource)) if resource
98
+ add_breadcrumb(resource_title_for(resource), path_to_edit(resource)) if resource
99
99
  end
100
100
 
101
101
  def attach_resource_to_component
@@ -107,6 +107,12 @@ module Para
107
107
  return unless @component.namespaced?
108
108
  @component.remove_resource(resource)
109
109
  end
110
+
111
+ def path_to_edit(resource)
112
+ @component.relation_path(
113
+ resource, action: (resource.persisted? ? :edit : :new)
114
+ )
115
+ end
110
116
  end
111
117
  end
112
118
  end
@@ -4,6 +4,20 @@ module Para
4
4
  def show
5
5
  @settings = SettingsRails::Form.new
6
6
  end
7
+
8
+ def update
9
+ form = SettingsRails::Form.new
10
+ form.settings_attributes = settings_params[:settings_attributes]
11
+ form.save
12
+ flash_message(:success, form)
13
+ redirect_to admin_settings_path(@component)
14
+ end
15
+
16
+ private
17
+
18
+ def settings_params
19
+ params.require(:resource).permit(settings_attributes: [:key, :_type, :value])
20
+ end
7
21
  end
8
22
  end
9
23
  end
@@ -8,15 +8,19 @@ module Para
8
8
  find_path([:admin, self, :resources], options)
9
9
  end
10
10
 
11
- def relation_path(controller_or_resource, options = {})
11
+ def relation_path(controller_or_resource, *nested_resources, **options)
12
+ id_key = nested_resources.empty? ? :id : :resource_id
13
+
12
14
  if (id = extract_id_from(controller_or_resource))
13
- options[:id] = id
15
+ options[id_key] = id
14
16
  end
15
17
 
16
- route_key = route_key_for(options[:id], options)
18
+ route_key = route_key_for(options[id_key], options)
17
19
  options[:model] = model_singular_route_key
18
20
 
19
- polymorphic_path([:admin, self, route_key].compact, options)
21
+ data = [:admin, self, route_key].compact + nested_resources
22
+
23
+ polymorphic_path(data, options)
20
24
  end
21
25
 
22
26
  private
@@ -66,9 +66,9 @@ module Para
66
66
  key = "#{ flash_shared_key }.#{ params[:action] }.#{ type }"
67
67
 
68
68
  translation = if resource
69
- I18n.t(key, model: resource.class.model_name.human)
69
+ ::I18n.t(key, model: resource.class.model_name.human)
70
70
  else
71
- I18n.t(key)
71
+ ::I18n.t(key)
72
72
  end
73
73
 
74
74
  flash[type] = translation
@@ -89,7 +89,9 @@ module Para
89
89
  end
90
90
 
91
91
  def partial_exists?(relation, partial)
92
- lookup_context.find_all("admin/#{relation}/_#{ partial }").any?
92
+ partial_path = partial.to_s.split('/')
93
+ partial_path[-1] = "_#{ partial_path.last }"
94
+ lookup_context.find_all("admin/#{relation}/#{ partial_path.join('/') }").any?
93
95
  end
94
96
  end
95
97
  end
@@ -0,0 +1,32 @@
1
+ module Para
2
+ module Admin
3
+ module PageHelper
4
+ def page_top_bar(options = {})
5
+ content_tag(:div, class: 'page-title') do
6
+ content_tag(:h1, options[:title]) +
7
+
8
+ if (actions = actions_for(options[:type]))
9
+ content_tag(:div, class: 'page-actions') do
10
+ actions.map(&method(:build_action)).join('').html_safe
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ def build_action(action)
17
+ link_to(action[:url], class: 'btn btn-default') do
18
+ (
19
+ (fa_icon(action[:icon]) if action[:icon]) +
20
+ action[:label]
21
+ ).html_safe
22
+ end
23
+ end
24
+
25
+ def actions_for(type)
26
+ Para.config.page_actions_for(type).map do |action|
27
+ instance_eval(&action)
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -30,7 +30,7 @@ module Para
30
30
  component.relation_path(resource),
31
31
  method: :delete,
32
32
  data: {
33
- confirm: I18n.t('para.list.delete_confirmation')
33
+ confirm: ::I18n.t('para.list.delete_confirmation')
34
34
  },
35
35
  class: 'btn btn-danger'
36
36
  ) do
@@ -38,4 +38,4 @@ module Para
38
38
  end
39
39
  end
40
40
  end
41
- end
41
+ end
@@ -19,7 +19,7 @@ module Para
19
19
  scope :ordered, -> { order(position: :asc) }
20
20
 
21
21
  def name
22
- read_attribute(:name) || I18n.t(
22
+ read_attribute(:name) || ::I18n.t(
23
23
  "components.component.#{ identifier }",
24
24
  default: identifier.humanize
25
25
  )
@@ -9,7 +9,7 @@ module Para
9
9
  validates :identifier, presence: true
10
10
 
11
11
  def name
12
- read_attribute(:name) || I18n.t(
12
+ read_attribute(:name) || ::I18n.t(
13
13
  "components.section.#{ identifier }",
14
14
  default: identifier.humanize
15
15
  )
@@ -0,0 +1,21 @@
1
+ module Para
2
+ module Page
3
+ class Section < ActiveRecord::Base
4
+ self.table_name = 'para_page_sections'
5
+
6
+ include Para::Sti::RootModel
7
+
8
+ acts_as_orderable
9
+
10
+ belongs_to :page, polymorphic: true
11
+
12
+ def self.subclasses_namespace
13
+ 'PageSection'
14
+ end
15
+
16
+ def css_class
17
+ @css_class ||= self.class.name.demodulize.underscore.gsub(/_/, '-')
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,7 +1,7 @@
1
1
  !!!
2
- %html{ lang: 'en' }
2
+ %html.body-full-height{ lang: 'en' }
3
3
  %head
4
- %title= Para.config.admin_title || I18n.t('para.admin.title')
4
+ %title= Para.config.admin_title || ::I18n.t('para.admin.title')
5
5
 
6
6
  %meta{ charset: 'utf-8' }/
7
7
  %meta{ content: 'IE=edge', 'http-equiv' => 'X-UA-Compatible' }/
@@ -1,4 +1,3 @@
1
- .page-title
2
- %h1= @component.name
1
+ = page_top_bar(title: @component.name, type: 'crud/index')
3
2
 
4
3
  = listing_for(@resources)
@@ -1,5 +1,4 @@
1
- .page-title
2
- %h1= t('para.dashboard.title')
1
+ = page_top_bar(title: t('para.dashboard.title'), type: 'dashboard/show')
3
2
 
4
3
  .page-content-wrap
5
4
  - ordered_components.each_slice(3) do |components|
@@ -1,8 +1,8 @@
1
1
  = resources_table(model: model, component: component) do |table|
2
2
  = table.header do
3
3
  - attributes.each do |field|
4
- = table.header_for(field.name)
4
+ = table.header_for(field.name.to_sym)
5
5
 
6
6
  = table.rows(resources) do |resource|
7
7
  - attributes.each do |field|
8
- = table.data_for(resource, field.name)
8
+ = table.data_for(resource, field.name.to_sym)
@@ -2,15 +2,18 @@
2
2
  .node-row
3
3
  %span.handle
4
4
  %i.fa.fa-bars.fa-fw
5
- %span.node-name
5
+ %span.node-name
6
6
  = root.name
7
+
7
8
  .pull-right.btn-group
8
9
  = link_to @component.relation_path(root, action: :edit, return_to: request.fullpath), class: "btn btn-primary" do
9
10
  %i.fa.fa-pencil
10
- = link_to @component.relation_path(root), method: :delete, data: { confirm: I18n.t('para.list.delete_confirmation') }, class: 'btn btn-danger' do
11
+
12
+ = link_to @component.relation_path(root), method: :delete, data: { confirm: ::I18n.t('para.list.delete_confirmation') }, class: 'btn btn-danger' do
11
13
  %i.fa.fa-trash
12
- .clearfix
14
+
15
+ .clearfix
13
16
  %ul.tree
14
17
  %li.placeholder{ class: "#{ 'hidden' unless needs_placeholder?(root) }"}
15
18
  = render partial: find_partial_for(model, 'tree_item'), collection: root.children.ordered, as: :root, locals: { model: model }
16
-
19
+
@@ -1,6 +1,4 @@
1
- .page-title
2
- %h1
3
- = resource_title_for(resource)
1
+ = page_top_bar(title: resource_title_for(resource), type: 'crud/edit')
4
2
 
5
3
  .page-content-wrap
6
4
  = render find_partial_for(resource, :form)
@@ -1,6 +1,4 @@
1
- .page-title
2
- %h1
3
- = resource_title_for(resource)
1
+ = page_top_bar(title: resource_title_for(resource), type: 'crud/new')
4
2
 
5
3
  .page-content-wrap
6
4
  = render find_partial_for(resource, :form)
@@ -1,8 +1,7 @@
1
- .page-title
2
- %h1= @component.name
1
+ = page_top_bar(title: @component.name, type: 'settings/show')
3
2
 
4
3
  .page-content-wrap
5
- = para_form_for @settings, url: admin_settings_settings_form_path(@component) do |form|
4
+ = para_form_for @settings, url: admin_settings_path(@component) do |form|
6
5
  = form.fieldset do
7
6
  - @component.settings.each do |setting, type|
8
7
  = form.settings_input setting, type: type
@@ -1,5 +1,4 @@
1
- .page-title
2
- %h1= @component.name
1
+ = page_top_bar(title: @component.name, type: 'singleton_resource/show')
3
2
 
4
3
  .page-content-wrap
5
4
  = render find_partial_for(resource, :form)
@@ -1,8 +1,7 @@
1
1
  .nested-many-field{ class: ('orderable' if orderable) }
2
2
  .fields-list{ id: dom_identifier }
3
3
  = form.simple_fields_for attribute_name, resources, nested_attribute_name: attribute_name, orderable: orderable do |nested_form|
4
- = render partial: find_partial_for(model, 'nested_many/container', partial_dir: 'inputs'), locals: { form: nested_form, model: model, subclass: subclass, nested_locals: nested_locals }
5
-
4
+ = render partial: find_partial_for(model, 'nested_many/container', partial_dir: 'inputs'), locals: { form: nested_form, model: nested_form.object.class, subclass: subclass, nested_locals: nested_locals }
6
5
  -# Add button
7
6
  - if add_button
8
7
  - if subclass
@@ -16,6 +16,7 @@
16
16
  .panel-body.form-inputs.collapse{ id: form.nested_resource_dom_id }
17
17
  = render partial: find_partial_for(model, :fields), locals: { form: form }.merge(nested_locals)
18
18
 
19
- = form.hidden_field :type if form.object.class.column_names.include?(form.object.class.inheritance_column)
19
+ -# Add inheritance column field if needed
20
+ = form.hidden_field form.object.class.inheritance_column if form.object.class.column_names.include?(form.object.class.inheritance_column)
20
21
 
21
22
  .clearfix
@@ -0,0 +1,12 @@
1
+ class CreateParaPageSections < ActiveRecord::Migration
2
+ def change
3
+ create_table :para_page_sections do |t|
4
+ t.string :type
5
+ t.jsonb :data
6
+ t.integer :position, default: 0
7
+ t.references :page, index: true, polymorphic: true
8
+
9
+ t.timestamps null: false
10
+ end
11
+ end
12
+ end
@@ -1,2 +1 @@
1
- .page-title
2
- %h1= @component.name
1
+ = page_top_bar(title: @component.name, type: '<%= file_name %>/show')
@@ -9,7 +9,7 @@ Para.config do |config|
9
9
  # config.pagination_theme = 'twitter-bootstrap-3'
10
10
 
11
11
  # Configure the default admin HTML page <title>
12
- # config.admin_title = I18n.t('para.admin.title')
12
+ # config.admin_title = ::I18n.t('para.admin.title')
13
13
 
14
14
  # Configure the default max depth for trees
15
15
  # config.default_tree_max_depth = 3
@@ -20,4 +20,8 @@ Para.config do |config|
20
20
  # Default is [:name, :title]
21
21
  #
22
22
  # config.resource_name_methods += [:full_name]
23
+
24
+ # Para plugins to load
25
+ #
26
+ # config.plugins = []
23
27
  end
@@ -16,8 +16,8 @@ module Para
16
16
 
17
17
  def generate_fields_container
18
18
  template(
19
- "../../../../../app/views/para/inputs/_nested_many_container.html.haml",
20
- "app/views/admin/#{ plural_namespaced_path }/_nested_many_container.html.haml"
19
+ "../../../../../app/views/para/inputs/nested_many/_container.html.haml",
20
+ "app/views/admin/#{ plural_namespaced_path }/nested_many/_container.html.haml"
21
21
  ) if options[:container]
22
22
  end
23
23
  end
@@ -0,0 +1,28 @@
1
+ module Para
2
+ module Page
3
+ class SectionGenerator < Rails::Generators::NamedBase
4
+ include Para::Generators::NameHelpers
5
+
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ argument :attributes, type: :array
9
+
10
+ def generate_form
11
+ template(
12
+ "section.rb.erb",
13
+ "app/models/page_section/#{ plural_namespaced_path }.rb"
14
+ )
15
+ end
16
+
17
+ private
18
+
19
+ def attributes_separated_with_commas
20
+ if attributes.empty?
21
+ ':title'
22
+ else
23
+ attributes.map { |attribute| ":#{ attribute.name }" }.join(', ')
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ module PageSection
2
+ class <%= class_name %> < Para::Page::Section
3
+ # Your page section fields are declared here as store accessors
4
+ store_accessor :data, <%= attributes_separated_with_commas %>
5
+ end
6
+ end
@@ -6,7 +6,7 @@ module Para
6
6
  field_option :wrapper, :wrapper_name
7
7
 
8
8
  def value_for(instance)
9
- I18n.t("para.types.boolean.#{ (!!instance.send(name)).to_s }")
9
+ ::I18n.t("para.types.boolean.#{ (!!instance.send(name)).to_s }")
10
10
  end
11
11
 
12
12
  def wrapper_name
@@ -6,7 +6,7 @@ module Para
6
6
  def value_for(instance)
7
7
  if (raw_value = instance.send(name)) &&
8
8
  path = enum_path_for(instance, raw_value)
9
- translation = I18n.t("activerecord.#{ path }", default: false)
9
+ translation = ::I18n.t("activerecord.#{ path }", default: false)
10
10
 
11
11
  translation || raw_value
12
12
  end
@@ -11,7 +11,7 @@ module Para
11
11
 
12
12
  def title
13
13
  @title ||= if Symbol === identifier
14
- I18n.t("admin.breadcrumbs.#{ identifier }")
14
+ ::I18n.t("admin.breadcrumbs.#{ identifier }")
15
15
  else
16
16
  identifier
17
17
  end
data/lib/para/config.rb CHANGED
@@ -18,11 +18,18 @@ module Para
18
18
  mattr_accessor :resource_name_methods
19
19
  @@resource_name_methods = [:admin_name, :admin_title, :name, :title]
20
20
 
21
+ mattr_accessor :plugins
22
+ @@plugins = []
23
+
24
+ # Hidden from initializer on purpose.
25
+ #
26
+ # This is mainly here to be overriden from a gem, not the app dev
27
+ #
21
28
  mattr_accessor :ability_class_name
22
29
  @@ability_class_name = 'Para::Ability'
23
30
 
24
- mattr_accessor :plugins
25
- @@plugins = []
31
+ mattr_accessor :page_actions
32
+ @@page_actions = {}
26
33
 
27
34
  # Allows accessing plugins root module to configure them through a method
28
35
  # from the Para::Config class.
@@ -41,5 +48,17 @@ module Para
41
48
  super
42
49
  end
43
50
  end
51
+
52
+ def self.routes
53
+ Para::Routes
54
+ end
55
+
56
+ def self.page_actions_for(type)
57
+ page_actions[type] ||= []
58
+ end
59
+
60
+ def self.add_actions_for(type, &block)
61
+ page_actions_for(type) << block
62
+ end
44
63
  end
45
64
  end
data/lib/para/engine.rb CHANGED
@@ -48,6 +48,14 @@ module Para
48
48
  end
49
49
  end
50
50
 
51
+ initializer 'Extend simple form extension selectize input' do
52
+ ActiveSupport.on_load(:active_record) do
53
+ ::SimpleFormExtension::Inputs::SelectizeInput.send(
54
+ :include, Para::Ext::SimpleFormExtension::SelectizeInput
55
+ )
56
+ end
57
+ end
58
+
51
59
  initializer 'Build components tree' do |app|
52
60
  components_config_path = Rails.root.join('config', 'components.rb')
53
61
 
@@ -55,5 +63,9 @@ module Para
55
63
  require components_config_path if File.exist?(components_config_path)
56
64
  end
57
65
  end
66
+
67
+ initializer 'Load page sections' do |app|
68
+ Para::Page::Section.eager_load!
69
+ end
58
70
  end
59
71
  end
@@ -0,0 +1,21 @@
1
+ module Para
2
+ module Ext
3
+ module SimpleFormExtension
4
+ module SelectizeInput
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ alias_method_chain :name_for, :admin_name
9
+ end
10
+
11
+ def name_for_with_admin_name(option)
12
+ Para.config.resource_name_methods.each do |method|
13
+ if (name = option.try(method))
14
+ return name
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
data/lib/para/ext.rb CHANGED
@@ -11,3 +11,4 @@ end
11
11
 
12
12
  require 'para/ext/cancan'
13
13
  require 'para/ext/paperclip'
14
+ require 'para/ext/simple_form_extension'
@@ -45,20 +45,20 @@ module Para
45
45
  end
46
46
 
47
47
  def para_submit_button(options = {})
48
- button(:submit, I18n.t('para.shared.save'), name: '_save', class: 'btn-success')
48
+ button(:submit, ::I18n.t('para.shared.save'), name: '_save', class: 'btn-success')
49
49
  end
50
50
 
51
51
  def para_submit_and_edit_button
52
- button(:submit, I18n.t('para.shared.save_and_edit'), name: '_save_and_edit', class: 'btn-primary')
52
+ button(:submit, ::I18n.t('para.shared.save_and_edit'), name: '_save_and_edit', class: 'btn-primary')
53
53
  end
54
54
 
55
55
  def para_submit_and_add_another_button
56
- button(:submit, I18n.t('para.shared.save_and_add_another_button'), name: '_save_and_add_another', class: 'btn-primary')
56
+ button(:submit, ::I18n.t('para.shared.save_and_add_another_button'), name: '_save_and_add_another', class: 'btn-primary')
57
57
  end
58
58
 
59
59
  def para_cancel_button
60
60
  template.link_to(
61
- I18n.t('para.shared.cancel'),
61
+ ::I18n.t('para.shared.cancel'),
62
62
  return_to_path,
63
63
  class: 'btn btn-danger'
64
64
  )
@@ -39,7 +39,7 @@ module Para
39
39
  self, wrapper_class: 'form-fields', class: 'btn btn-danger'
40
40
  ) do
41
41
  template.content_tag(:i, '', class: 'fa fa-trash') +
42
- I18n.t('para.form.nested.remove')
42
+ ::I18n.t('para.form.nested.remove')
43
43
  end
44
44
  end
45
45
  end
@@ -75,7 +75,7 @@ module Para
75
75
 
76
76
  def default_resource_name
77
77
  model_name = object.class.model_name.human
78
- id_or_new = (id = object.id) ? id : I18n.t('para.form.nested.new')
78
+ id_or_new = (id = object.id) ? id : ::I18n.t('para.form.nested.new')
79
79
 
80
80
  [model_name, id_or_new].join(' - ')
81
81
  end
@@ -41,7 +41,7 @@ module Para
41
41
 
42
42
  def title
43
43
  if Symbol === identifier
44
- I18n.t("forms.tabs.#{ object.class.model_name.i18n_key }.#{ identifier }")
44
+ ::I18n.t("forms.tabs.#{ object.class.model_name.i18n_key }.#{ identifier }")
45
45
  else
46
46
  identifier
47
47
  end
@@ -10,12 +10,19 @@ module Para
10
10
  end
11
11
  end
12
12
 
13
- def field_options_for(field)
14
- field_options = field.field_options
13
+ def field_options_for(field, options = {})
14
+ field_options = field.field_options.merge(options)
15
15
 
16
16
  options = field_options.each_with_object([]) do |(key, value), ary|
17
17
  if writable_value?(value)
18
- ary << "#{ key.inspect } => #{ value.inspect }"
18
+ if key.to_s.match(/^[\w\d]+/)
19
+ join_symbol = ': '
20
+ else
21
+ join_symbol = ' => '
22
+ key = key.inspect
23
+ end
24
+
25
+ ary << [key, join_symbol, value.inspect].join
19
26
  end
20
27
  end
21
28
 
@@ -1,6 +1,8 @@
1
1
  module Para
2
2
  module Inputs
3
3
  class NestedManyInput < SimpleForm::Inputs::Base
4
+ attr_reader :resource
5
+
4
6
  def input(wrapper_options = nil)
5
7
  input_html_options[:class] << "nested-many"
6
8
 
@@ -1,6 +1,9 @@
1
1
  module Para
2
2
  module Markup
3
3
  class ResourcesTable < Para::Markup::Component
4
+ class_attribute :default_actions
5
+ self.default_actions = [:edit, :clone, :delete]
6
+
4
7
  attr_reader :model, :component, :orderable, :actions
5
8
 
6
9
  def container(options = {}, &block)
@@ -11,7 +14,7 @@ module Para
11
14
  @orderable = model.orderable?
12
15
  end
13
16
 
14
- @actions = options.fetch(:actions, true)
17
+ @actions = build_actions(options.delete(:actions))
15
18
 
16
19
  merge_class!(options, 'table')
17
20
  merge_class!(options, 'para-component-relation-table')
@@ -41,7 +44,7 @@ module Para
41
44
  # Append cells
42
45
  cells << capture { block.call }
43
46
  # Append actions empty cell
44
- cells << content_tag(:th, '', class: 'actions') if actions
47
+ cells << content_tag(:th, '', class: 'actions', width: 1) if actions
45
48
 
46
49
  # Output full header
47
50
  content_tag(:thead) do
@@ -132,11 +135,9 @@ module Para
132
135
  def actions_cell(resource)
133
136
  content_tag(:td) do
134
137
  content_tag(:div, class: 'pull-right btn-group') do
135
- edit = edit_button(resource) if action?(:edit)
136
- clone = clone_button(resource) if action?(:clone)
137
- delete = delete_button(resource) if action?(:delete)
138
-
139
- edit + clone + delete
138
+ actions.map do |type|
139
+ send(:"#{ type }_button", resource)
140
+ end.compact.join.html_safe
140
141
  end
141
142
  end
142
143
  end
@@ -174,7 +175,7 @@ module Para
174
175
  options = {
175
176
  method: :delete,
176
177
  data: {
177
- confirm: I18n.t('para.list.delete_confirmation')
178
+ confirm: ::I18n.t('para.list.delete_confirmation')
178
179
  },
179
180
  class: 'btn btn-danger'
180
181
  }
@@ -194,8 +195,12 @@ module Para
194
195
  model.columns_hash.keys.include?(field_name.to_s)
195
196
  end
196
197
 
197
- def action?(type)
198
- actions == true || actions.include?(type)
198
+ def build_actions(actions)
199
+ if actions.in?([true, nil])
200
+ default_actions
201
+ else
202
+ actions
203
+ end
199
204
  end
200
205
  end
201
206
  end
@@ -4,6 +4,11 @@ module Para
4
4
  register :json, self
5
5
 
6
6
  def parse!
7
+ process_stored_attributes
8
+ process_remaining_json_fields
9
+ end
10
+
11
+ def process_stored_attributes
7
12
  model.stored_attributes.each do |store_key, field_names|
8
13
  fields_hash.delete(store_key)
9
14
 
@@ -15,8 +20,26 @@ module Para
15
20
  end
16
21
  end
17
22
 
23
+ # Duplicate fields to avoid updating the hash while iterating through it
24
+ # then remove remaining json fields from the hash
25
+ def process_remaining_json_fields
26
+ fields_hash.dup.each do |key, field|
27
+ fields_hash.delete(key) if json_field?(field)
28
+ end
29
+ end
30
+
18
31
  def applicable?
19
- !model.stored_attributes.empty?
32
+ !model.stored_attributes.empty? || model_includes_json_fields?
33
+ end
34
+
35
+ def model_includes_json_fields?
36
+ fields_hash.any? do |_, field|
37
+ json_field?(field)
38
+ end
39
+ end
40
+
41
+ def json_field?(field)
42
+ field.type.to_s.in?(%w(json jsonb))
20
43
  end
21
44
  end
22
45
  end
@@ -0,0 +1,12 @@
1
+ module Para
2
+ module Page
3
+ module Model
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ has_many :sections, -> { ordered }, class_name: '::Para::Page::Section', as: :page
8
+ accepts_nested_attributes_for :sections, allow_destroy: true
9
+ end
10
+ end
11
+ end
12
+ end
data/lib/para/page.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Para
2
+ module Page
3
+ end
4
+ end
5
+
6
+ require 'para/page/model'
data/lib/para/routes.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Para
2
2
  class Routes
3
+ class_attribute :routes_extensions
4
+
3
5
  attr_reader :router
4
6
 
5
7
  def initialize(router)
@@ -15,6 +17,7 @@ module Para
15
17
 
16
18
  crud_component :crud, scope: ':model'
17
19
  singleton_resource_component :singleton, scope: ':model'
20
+ component :settings
18
21
  end
19
22
  end
20
23
 
@@ -22,5 +25,15 @@ module Para
22
25
  end
23
26
  end
24
27
  end
28
+
29
+ def self.extend_routes_for(component_type, &block)
30
+ extensions = routes_extensions_for(component_type)
31
+ extensions << block
32
+ end
33
+
34
+ def self.routes_extensions_for(component_type)
35
+ self.routes_extensions ||= {}
36
+ self.routes_extensions[component_type] ||= []
37
+ end
25
38
  end
26
39
  end
@@ -0,0 +1,58 @@
1
+ module Para
2
+ module Sti
3
+ module RootModel
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class << self
8
+ def descendants_with_eager_loaded_subclasses
9
+ eager_load!
10
+ descendants_without_eager_loaded_subclasses
11
+ end
12
+
13
+ alias_method_chain :descendants, :eager_loaded_subclasses
14
+ end
15
+ end
16
+
17
+ module ClassMethods
18
+ def eager_load!
19
+ return if @eager_loaded
20
+ @eager_loaded = true
21
+
22
+ models_dir = Rails.root.join('app', 'models')
23
+
24
+ Dir[models_dir.join(subclasses_dir, '*.rb')].each do |file_path|
25
+ file_name = File.basename(file_path, '.rb')
26
+
27
+ # Avoid Circular dependecy errors in development, when the first
28
+ # loaded class is not the base class. In this case, the base class
29
+ # loading is triggered by the child, so if we try to load that child
30
+ # again, Rails issues a CircularDependency error
31
+ file_load_path = File.join(File.dirname(file_path), file_name)
32
+ next if ActiveSupport::Dependencies.loading.include?(file_load_path)
33
+
34
+ # Autoload the subclass
35
+ require file_load_path
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # Allows the including class to define `.subclasses_namespace` class
42
+ # method to override the namespace and directory used to eager load the
43
+ # subclasses.
44
+ #
45
+ # Note : No error is raised if target subclasses directory does not
46
+ # exist.
47
+ #
48
+ def subclasses_namespace
49
+ @subclasses_namespace ||= name.deconstantize
50
+ end
51
+
52
+ def subclasses_dir
53
+ @subclasses_dir ||= subclasses_namespace.underscore
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
data/lib/para/sti.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Para
2
+ module Sti
3
+ end
4
+ end
5
+
6
+ require 'para/sti/root_model'
data/lib/para/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Para
2
- VERSION = "0.5.1"
2
+ VERSION = "0.5.3"
3
3
  end
data/lib/para.rb CHANGED
@@ -8,6 +8,7 @@ require 'truncate_html'
8
8
  require 'cocoon'
9
9
  require 'cancan'
10
10
  require 'request_store'
11
+ require 'roo'
11
12
 
12
13
  require 'sass-rails'
13
14
  require 'selectize-rails'
@@ -32,6 +33,8 @@ require 'para/engine'
32
33
  require 'para/components_configuration'
33
34
  require 'para/exporter'
34
35
  require 'para/importer'
36
+ require 'para/sti'
37
+ require 'para/page'
35
38
 
36
39
  module Para
37
40
  extend ActiveSupport::Autoload
@@ -27,7 +27,7 @@ class RelationLengthValidator < ActiveModel::EachValidator
27
27
 
28
28
  def smaller_error_message
29
29
  message = options[:message] && options[:message][:minimum]
30
- message || I18n.t(
30
+ message || ::I18n.t(
31
31
  "activerecord.errors.relation_length_is_smaller",
32
32
  minimum: minimum,
33
33
  default: "must have at least #{ minimum } elements"
@@ -36,7 +36,7 @@ class RelationLengthValidator < ActiveModel::EachValidator
36
36
 
37
37
  def greater_error_message
38
38
  message = options[:message] && options[:message][:maximum]
39
- message || I18n.t(
39
+ message || ::I18n.t(
40
40
  "activerecord.errors.relation_length_is_greater",
41
41
  maximum: maximum,
42
42
  default: "must have at most #{ maximum } elements"
@@ -20,7 +20,11 @@ module ActionDispatch
20
20
  )
21
21
 
22
22
  get endpoint => "#{ controller }#show", as: as
23
- scope(endpoint, as: component_name, &block) if block
23
+
24
+ scope(endpoint, as: component_name) do
25
+ instance_eval(&block) if block
26
+ add_extensions_for(:component)
27
+ end
24
28
  end
25
29
 
26
30
  def crud_component(component_name, options = {}, &block)
@@ -45,6 +49,7 @@ module ActionDispatch
45
49
  end
46
50
 
47
51
  instance_eval(&block) if block
52
+ add_extensions_for(:crud_component)
48
53
  end
49
54
  end
50
55
  end
@@ -59,6 +64,7 @@ module ActionDispatch
59
64
 
60
65
  scope endpoint, as: as do
61
66
  resource :resource, controller: controller, only: [:show, :create, :update]
67
+ add_extensions_for(:singleton_resource_component)
62
68
  end
63
69
  end
64
70
 
@@ -81,6 +87,12 @@ module ActionDispatch
81
87
 
82
88
  [as, controller, endpoint]
83
89
  end
90
+
91
+ def add_extensions_for(type)
92
+ Para.config.routes.routes_extensions_for(type).each do |extension|
93
+ instance_eval(&extension)
94
+ end
95
+ end
84
96
  end
85
97
  end
86
98
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: para
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Valentin Ballestrino
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-08 00:00:00.000000000 Z
11
+ date: 2016-05-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -192,6 +192,20 @@ dependencies:
192
192
  - - ">="
193
193
  - !ruby/object:Gem::Version
194
194
  version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: roo
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
195
209
  - !ruby/object:Gem::Dependency
196
210
  name: bootstrap-sass
197
211
  requirement: !ruby/object:Gem::Requirement
@@ -347,6 +361,7 @@ files:
347
361
  - app/assets/stylesheets/para/admin/src/fuelux.sass
348
362
  - app/assets/stylesheets/para/admin/src/jasny.bootstrap.sass
349
363
  - app/assets/stylesheets/para/admin/src/page-loading.sass
364
+ - app/assets/stylesheets/para/admin/src/page-top-bar.sass
350
365
  - app/assets/stylesheets/para/admin/src/redactor.sass
351
366
  - app/assets/stylesheets/para/admin/src/selectize.sass
352
367
  - app/assets/stylesheets/para/admin/src/slider.sass
@@ -379,7 +394,6 @@ files:
379
394
  - app/controllers/para/admin/main_controller.rb
380
395
  - app/controllers/para/admin/resources_controller.rb
381
396
  - app/controllers/para/admin/settings_component_controller.rb
382
- - app/controllers/para/admin/settings_form_controller.rb
383
397
  - app/controllers/para/admin/singleton_resources_controller.rb
384
398
  - app/controllers/para/application_controller.rb
385
399
  - app/decorators/para/component/base_decorator.rb
@@ -390,6 +404,7 @@ files:
390
404
  - app/helpers/para/admin/base_helper.rb
391
405
  - app/helpers/para/admin/component_groups_helper.rb
392
406
  - app/helpers/para/admin/components_helper.rb
407
+ - app/helpers/para/admin/page_helper.rb
393
408
  - app/helpers/para/admin/resources_helper.rb
394
409
  - app/helpers/para/application_helper.rb
395
410
  - app/helpers/para/exports_helper.rb
@@ -410,9 +425,9 @@ files:
410
425
  - app/models/para/component/singleton_resource.rb
411
426
  - app/models/para/component_resource.rb
412
427
  - app/models/para/component_section.rb
428
+ - app/models/para/page/section.rb
413
429
  - app/views/layouts/para/admin.html.haml
414
430
  - app/views/layouts/para/application.html.erb
415
- - app/views/para/admin/crud_component/show.html.haml
416
431
  - app/views/para/admin/crud_resources/index.html.haml
417
432
  - app/views/para/admin/dashboard.html.haml
418
433
  - app/views/para/admin/main/index.html.haml
@@ -451,6 +466,7 @@ files:
451
466
  - db/migrate/20150129170710_create_para_component_resources.rb
452
467
  - db/migrate/20150203173219_add_identifier_to_para_components.rb
453
468
  - db/migrate/20160304113055_add_json_equality_operator_patch_to_postgres.rb
469
+ - db/migrate/20160419145254_create_para_page_sections.rb
454
470
  - lib/generators/para/admin_user/admin_user_generator.rb
455
471
  - lib/generators/para/component/component_generator.rb
456
472
  - lib/generators/para/component/crud/crud_generator.rb
@@ -475,6 +491,8 @@ files:
475
491
  - lib/generators/para/nested_fields/templates/_nested_fields.html.haml
476
492
  - lib/generators/para/orderable/orderable_generator.rb
477
493
  - lib/generators/para/orderable/templates/orderable_migration.rb
494
+ - lib/generators/para/page/section/section_generator.rb
495
+ - lib/generators/para/page/section/templates/section.rb.erb
478
496
  - lib/generators/para/resource/resource_generator.rb
479
497
  - lib/generators/para/resource/templates/resource_controller.rb
480
498
  - lib/generators/para/table/table_generator.rb
@@ -515,6 +533,7 @@ files:
515
533
  - lib/para/ext.rb
516
534
  - lib/para/ext/cancan.rb
517
535
  - lib/para/ext/paperclip.rb
536
+ - lib/para/ext/simple_form_extension.rb
518
537
  - lib/para/form_builder.rb
519
538
  - lib/para/form_builder/containers.rb
520
539
  - lib/para/form_builder/field_mappings.rb
@@ -549,9 +568,13 @@ files:
549
568
  - lib/para/model_field_parsers/relations.rb
550
569
  - lib/para/model_field_parsers/store.rb
551
570
  - lib/para/orderable.rb
571
+ - lib/para/page.rb
572
+ - lib/para/page/model.rb
552
573
  - lib/para/plugins.rb
553
574
  - lib/para/plugins/routes.rb
554
575
  - lib/para/routes.rb
576
+ - lib/para/sti.rb
577
+ - lib/para/sti/root_model.rb
555
578
  - lib/para/version.rb
556
579
  - lib/rails/relation_length_validator.rb
557
580
  - lib/rails/routing_mapper.rb
@@ -1,21 +0,0 @@
1
- module Para
2
- module Admin
3
- class SettingsFormController < Para::Admin::BaseController
4
- load_and_authorize_component
5
-
6
- def update
7
- form = SettingsRails::Form.new
8
- form.settings_attributes = settings_params[:settings_attributes]
9
- form.save
10
- flash_message(:success, form)
11
- redirect_to admin_settings_path(@component)
12
- end
13
-
14
- private
15
-
16
- def settings_params
17
- params.require(:resource).permit(settings_attributes: [:key, :_type, :value])
18
- end
19
- end
20
- end
21
- end
@@ -1,4 +0,0 @@
1
- .page-title
2
- %h1= @component.name
3
-
4
- = listing_for(@resources)