alchemy-custom-model 2.0.2 → 2.2.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.
Files changed (44) hide show
  1. checksums.yaml +5 -5
  2. data/app/assets/javascripts/alchemy-custom-model/alchemy_custom_model_select.js +62 -0
  3. data/app/assets/javascripts/alchemy-custom-model/common_init.js +17 -14
  4. data/app/assets/javascripts/alchemy-custom-model/el_finder.js.coffee.erb +31 -0
  5. data/app/assets/javascripts/alchemy-custom-model/manifest.js +5 -0
  6. data/app/assets/javascripts/alchemy-custom-model/total_page_elfinder.js.coffee +1 -1
  7. data/app/assets/javascripts/backend/date_picker.js +24 -0
  8. data/app/assets/javascripts/backend/fix_more_image_in_element.js.coffee +10 -0
  9. data/app/assets/javascripts/backend/override_alchemy_selectbox.js +8 -0
  10. data/app/assets/stylesheets/alchemy-custom-model/custom_elfinder.css.scss +20 -2
  11. data/app/controllers/alchemy/custom/model/admin/base_controller.rb +49 -0
  12. data/app/controllers/alchemy/custom/model/admin/base_with_globalize_controller.rb +38 -0
  13. data/app/controllers/concerns/alchemy/admin/nodes_controller_dec.rb +55 -0
  14. data/app/helpers/alchemy/custom/model/admin/base_helper.rb +5 -2
  15. data/app/helpers/alchemy/pages_helper_decorator.rb +38 -0
  16. data/app/models/concerns/alchemy/node_dec.rb +45 -0
  17. data/app/views/alchemy/admin/nodes/_form.html.erb +126 -0
  18. data/app/views/alchemy/admin/nodes/custom_models.json.jbuilder +10 -0
  19. data/app/views/alchemy/admin/nodes/custom_models_methods.json.jbuilder +10 -0
  20. data/app/views/alchemy/admin/pictures/_custom_model_info.html.erb +27 -0
  21. data/app/views/alchemy/admin/pictures/_infos.html.erb +65 -0
  22. data/app/views/alchemy/custom/model/admin/base/_gallery_item.html.erb +7 -2
  23. data/app/views/alchemy/custom/model/admin/base/_seo.html.erb +5 -5
  24. data/app/views/alchemy/custom/model/admin/base/_title.html.erb +1 -1
  25. data/app/views/alchemy/custom/model/admin/base/edit.html.erb +2 -2
  26. data/app/views/alchemy/custom/model/admin/base/index.html.erb +23 -2
  27. data/app/views/alchemy/custom/model/admin/base/new.html.erb +2 -2
  28. data/app/views/alchemy/custom/model/admin/base/show.html.erb +2 -2
  29. data/config/locales/it.yml +6 -0
  30. data/config/routes.rb +16 -0
  31. data/db/migrate/20200424184007_add_fields_to_node.rb +8 -0
  32. data/lib/{alchemy-custom-model.rb → alchemy/custom/model.rb} +20 -0
  33. data/lib/alchemy/custom/model/engine.rb +7 -1
  34. data/lib/alchemy/custom/model/globalize_model_decoration.rb +25 -0
  35. data/lib/alchemy/custom/model/menu_methods.rb +16 -0
  36. data/lib/alchemy/custom/model/model_decoration.rb +2 -0
  37. data/lib/alchemy/custom/model/model_utils_methods.rb +28 -0
  38. data/lib/alchemy/custom/model/order.rb +1 -1
  39. data/lib/alchemy/custom/model/picture_used_by.rb +51 -0
  40. data/lib/alchemy/custom/model/slug_optimizer.rb +23 -0
  41. data/lib/alchemy/custom/model/version.rb +1 -1
  42. data/lib/tasks/alchemy_custom_model_tasks.rake +3 -0
  43. data/vendor/assets/javascripts/flatpickr/i10n/it.js +71 -0
  44. metadata +53 -7
@@ -91,5 +91,43 @@ Alchemy::PagesHelper.module_eval do
91
91
  end
92
92
 
93
93
 
94
+ def check_if_active node_or_cm_inst
95
+ if !node_or_cm_inst.is_a? Alchemy::Node
96
+ if node_or_cm_inst.respond_to? :for_menu_matching and node_or_cm_inst.for_menu_matching.include? @custom_element
97
+ return true
98
+ end
99
+ else
100
+ if node_or_cm_inst.custom_model?
101
+ if @custom_element.respond_to? :for_menu_matching and
102
+ @custom_element.for_menu_matching.include? node_or_cm_inst.klass_custom_model
103
+ return true
104
+ end
105
+ elsif node_or_cm_inst.page and node_or_cm_inst.page.self_and_descendants.include? @page
106
+ return true
107
+ end
108
+ end
109
+ false
110
+ end
111
+
112
+ def render_menu_with_language(name, options = {})
113
+ root_node = Alchemy::Node.where(language_id: Alchemy::Language.current.id).roots.find_by(name: name)
114
+ if root_node.nil?
115
+ warning("Menu with name #{name} not found!")
116
+ return
117
+ end
118
+
119
+ options = {
120
+ node_partial_name: "#{root_node.view_folder_name}/node"
121
+ }.merge(options)
122
+
123
+ render(root_node, menu: root_node, node: root_node, options: options)
124
+ rescue ActionView::MissingTemplate => e
125
+ warning <<-WARN
126
+ Menu partial not found for #{name}.
127
+ #{e}
128
+ WARN
129
+ end
130
+
131
+
94
132
  end
95
133
 
@@ -0,0 +1,45 @@
1
+ module Alchemy
2
+ module NodeDec
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+
8
+ validates :custom_model_klass, presence: true, if: -> {
9
+ url.blank? and not parent.nil?
10
+ }
11
+
12
+ before_validation :ensure_page_nil_if_custom_model, on: [:create, :update]
13
+ before_validation :set_site, on: [:create], if: -> {site.nil?}
14
+
15
+ def custom_model?
16
+ !custom_model_klass.blank?
17
+ end
18
+
19
+ def klass_custom_model
20
+ self.custom_model_klass.constantize
21
+ end
22
+
23
+ private
24
+
25
+ def ensure_page_nil_if_custom_model
26
+ if not url.blank? and !custom_model_klass_changed? and !custom_model_method_changed?
27
+ self.custom_model_klass = nil
28
+ self.custom_model_method = nil
29
+ elsif !custom_model_klass.blank? and !url_changed?
30
+ self.page = nil
31
+ self.url = nil
32
+ end
33
+
34
+ end
35
+
36
+ def set_site
37
+ unless self.language.nil?
38
+ self.site = language.site
39
+ end
40
+ end
41
+
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,126 @@
1
+ <%= alchemy_form_for([:admin, node]) do |f| %>
2
+
3
+ <% if node.root? %>
4
+
5
+ <% if Alchemy::Node.respond_to? :available_menu_names %>
6
+ <%= f.input :name,
7
+ collection: Alchemy::Node.available_menu_names.map { |n| [I18n.t(n, scope: [:alchemy, :menu_names]), n] },
8
+ include_blank: false,
9
+ input_html: {class: 'alchemy_selectbox'} %>
10
+ <% else %>
11
+ <%= f.input :name, input_html: {
12
+ autofocus: true,
13
+ value: node.page && node.read_attribute(:name).blank? ? nil : node.name,
14
+ placeholder: node.page ? node.page.name : nil
15
+ } %>
16
+ <% end %>
17
+
18
+ <% else %>
19
+
20
+ <%= f.input :name, as: :string, input_html: {
21
+ autofocus: true,
22
+ value: node.page && node.read_attribute(:name).blank? ? nil : node.name,
23
+ placeholder: node.page ? node.page.name : nil
24
+ } %>
25
+
26
+ <%
27
+ active_klass = (node.errors.keys.include? :custom_model_klass or
28
+ node.custom_model?) ? "ui-tabs-active" : ""
29
+ %>
30
+
31
+ <div class="container_selctor_age_custom_model">
32
+ <div id="tabs_nodes" class="ui-tabs ui-corner-all ui-widget ui-widget-content">
33
+ <ul role="tablist" class="ui-tabs-nav ui-corner-all ui-helper-reset ui-helper-clearfix ui-widget-header">
34
+ <li role="tab" tabindex="0" class="ui-tabs-tab ui-corner-top ui-state-default ui-tab">
35
+ <a href="#pages" role="presentation" tabindex="-1" class="ui-tabs-anchor" id="ui-id-1">
36
+ <%= Alchemy.t(:pages_select) %>
37
+ </a>
38
+ </li>
39
+ <li role="tab" tabindex="1" class="ui-tabs-tab ui-corner-top ui-tab <%= active_klass %>">
40
+ <a href="#custom_models" role="presentation" tabindex="1" class="ui-tabs-anchor" id="ui-id-2">
41
+ <%= Alchemy.t(:custom_models) %>
42
+ </a>
43
+ </li>
44
+ </ul>
45
+ <div id="custom_models" aria-labelledby="legacy_urls_label" role="tabpanel" class="ui-tabs-panel ui-corner-bottom ui-widget-content" aria-hidden="false">
46
+ <%= f.input :custom_model_klass, input_html: {class: 'alchemy_selectbox'} %>
47
+ <%= f.input :custom_model_method, input_html: {class: 'alchemy_selectbox'} %>
48
+ </div>
49
+ <div id="pages" aria-labelledby="ui-id-1" role="tabpanel" class="ui-tabs-panel ui-corner-bottom ui-widget-content" aria-hidden="false">
50
+ <%= f.input :page_id, label: Alchemy::Page.model_name.human, input_html: {class: 'alchemy_selectbox'} %>
51
+ <%= f.input :url, input_html: {disabled: node.page}, hint: Alchemy.t(:node_url_hint) %>
52
+ <%= f.input :title %>
53
+ <%= f.input :nofollow %>
54
+ <%= f.input :external %>
55
+ <%= f.hidden_field :parent_id %>
56
+ </div>
57
+
58
+ </div>
59
+ </div>
60
+
61
+
62
+
63
+
64
+
65
+
66
+ <% end %>
67
+ <% if node.respond_to? :site_id %>
68
+ <%= f.hidden_field :site_id %>
69
+ <% end %>
70
+ <% if node.respond_to? :language_id %>
71
+ <%= f.hidden_field :language_id %>
72
+ <% end %>
73
+ <%= f.submit button_label %>
74
+ <% end %>
75
+
76
+ <script>
77
+
78
+ $("#tabs_nodes").tabs();
79
+
80
+
81
+ $('#node_custom_model_klass').alchemyCustomModelSelect({
82
+ placeholder: "<%= Alchemy.t(:select_custom_model_method) %>",
83
+ url: "<%= alchemy.custom_models_admin_nodes_path %>",
84
+
85
+ }).on("change", function (event) {
86
+ $('#node_custom_model_method').select2('enable');
87
+
88
+ }).on("select2-removed", function (e) {
89
+ $('#node_custom_model_method').val(null).trigger("change");
90
+ })
91
+
92
+
93
+ $('#node_custom_model_method').alchemyCustomModelSelect({
94
+ placeholder: "<%= Alchemy.t(:select_custom_model) %>",
95
+ url: "<%= alchemy.custom_models_methods_admin_nodes_path %>",
96
+ query_params: function (term, page) {
97
+ var klass = $('#node_custom_model_klass').val()
98
+ return {
99
+ custom_model_klass: klass
100
+ }
101
+ }
102
+
103
+ })
104
+
105
+ $('#node_custom_model_method').select2('disable');
106
+
107
+ $('#node_page_id').alchemyPageSelect({
108
+ placeholder: "<%= Alchemy.t(:search_page) %>",
109
+ url: "<%= alchemy.api_pages_path %>",
110
+ <% if node.page %>
111
+ initialSelection: {
112
+ id: <%= node.page_id %>,
113
+ text: "<%= node.page.name %>",
114
+ url: "/<%= node.page.urlname %>"
115
+ }
116
+ <% end %>
117
+ }).on('change', function (e) {
118
+ if (e.val === '') {
119
+ $('#node_name').removeAttr('placeholder')
120
+ $('#node_url').val('').prop('disabled', false)
121
+ } else {
122
+ $('#node_name').attr('placeholder', e.added.name)
123
+ $('#node_url').val('/' + e.added.urlname).prop('disabled', true)
124
+ }
125
+ })
126
+ </script>
@@ -0,0 +1,10 @@
1
+
2
+ json.meta do
3
+ json.total_count @custom_model_klasses.count
4
+ json.page params[:page]
5
+ json.per_page 10
6
+ end
7
+ json.results @custom_model_klasses do |result|
8
+ json.id result
9
+ json.text result
10
+ end
@@ -0,0 +1,10 @@
1
+
2
+ json.meta do
3
+ json.total_count @custom_model_methods.count
4
+ json.page params[:page]
5
+ json.per_page 10
6
+ end
7
+ json.results @custom_model_methods do |result|
8
+ json.id result
9
+ json.text result
10
+ end
@@ -0,0 +1,27 @@
1
+ <div class="picture-usage-info resource_info">
2
+ <h3>
3
+ <%= I18n.t(:image_used_in_this_models, scope: :alchemy_custom_model) %>
4
+ </h3>
5
+ <div id="pictures_page_list">
6
+ <% used_in = Alchemy::Custom::Model::PictureUsedBy.used_by(@picture.id)%>
7
+ <% if used_in.any? %>
8
+ <ul>
9
+ <% used_in.each do |m| %>
10
+ <li>
11
+ <% begin %>
12
+ <h3>
13
+ <%= render_icon 'file-alt' %>
14
+ <p><%= link_to "#{m.model_name.human}, #{m.try(:slug).to_s}", main_app.edit_polymorphic_path([:admin, m]) %></p>
15
+ </h3>
16
+ <% rescue %>
17
+ <% end %>
18
+ </li>
19
+ <% end %>
20
+ </ul>
21
+ <% else %>
22
+ <%= render_message do %>
23
+ <%= Alchemy.t(:picture_not_in_use_yet) %>
24
+ <% end %>
25
+ <% end %>
26
+ </div>
27
+ </div>
@@ -0,0 +1,65 @@
1
+ <div class="resource_info">
2
+ <div class="picture-file-infos">
3
+ <div class="value">
4
+ <label><%= Alchemy::Picture.human_attribute_name(:image_file_name) %></label>
5
+ <p><%= @picture.image_file_name %></p>
6
+ </div>
7
+ <div class="value">
8
+ <label><%= Alchemy::Picture.human_attribute_name(:image_file_dimensions) %></label>
9
+ <p><%= @picture.image_file_dimensions %>px</p>
10
+ </div>
11
+ <div class="value">
12
+ <label><%= Alchemy::Picture.human_attribute_name(:image_file_size) %></label>
13
+ <p><%= number_to_human_size @picture.image_file_size %></p>
14
+ </div>
15
+ </div>
16
+ </div>
17
+
18
+ <div class="picture-usage-info resource_info">
19
+ <h3>
20
+ <%= Alchemy.t(:this_picture_is_used_on_these_pages) %>
21
+ </h3>
22
+ <div id="pictures_page_list">
23
+ <% if @assignments.any? %>
24
+ <ul>
25
+ <% @assignments.group_by(&:page).each do |page, essence_pictures| %>
26
+ <% if page %>
27
+ <li>
28
+ <h3>
29
+ <%= render_icon 'file-alt' %>
30
+ <p><%= link_to page.name, edit_admin_page_path(page) %></p>
31
+ </h3>
32
+ <ul class="list">
33
+ <% essence_pictures.group_by(&:element).each do |element, essence_pictures| %>
34
+ <li class="<%= cycle('even', 'odd') %>">
35
+ <% page_link = link_to element.display_name_with_preview_text,
36
+ edit_admin_page_path(page, anchor: "element_#{element.id}") %>
37
+ <% pictures = essence_pictures.collect do |e|
38
+ e.content.name_for_label
39
+ end.to_sentence %>
40
+ <% if element.public? %>
41
+ <%= render_icon('window-maximize', style: 'regular') %>
42
+ <% else %>
43
+ <%= render_icon('window-close') %>
44
+ <% end %>
45
+ <p>
46
+ <%== Alchemy.t(:pictures_in_page, page: page_link, pictures: pictures) %>
47
+ <em><%= Alchemy::Element.human_attribute_name(:trashed) if element.trashed? %></em>
48
+ </p>
49
+ </li>
50
+ <% end %>
51
+ </ul>
52
+ </li>
53
+ <% end %>
54
+ <% end %>
55
+ </ul>
56
+ <% else %>
57
+ <%= render_message do %>
58
+ <%= Alchemy.t(:picture_not_in_use_yet) %>
59
+ <% end %>
60
+ <% end %>
61
+ </div>
62
+ </div>
63
+
64
+ <%= render partial: "custom_model_info" %>
65
+
@@ -1,4 +1,9 @@
1
- <div class="gallery_item_blk">
2
- <%= image_tag(picture.image_file.thumb("100x100#").url) %>
1
+ <div class="gallery_item_blk" data-id="<%= jr_id %>">
2
+ <%= image_tag(picture.image_file.thumb("140x140#").url) %>
3
3
  <%= yield if block_given? %>
4
+ <div class="command_area">
5
+ <div class="destroy">
6
+ <i class="fas fa-times fa-lg fa-fw"></i>
7
+ </div>
8
+ </div>
4
9
  </div>
@@ -1,8 +1,8 @@
1
1
  <fieldset>
2
2
  <legend><%= t(:seo_fields)%></legend>
3
- <%= f.input :meta_title %>
4
- <%= f.input :meta_description %>
5
- <%= f.input :meta_keywords %>
6
- <%= f.input :robot_follow %>
7
- <%= f.input :robot_index %>
3
+ <%= f.input :meta_title, as: :string %>
4
+ <%= f.input :meta_description, as: :text%>
5
+ <%= f.input :meta_keywords, as: :text %>
6
+ <%= f.input :robot_follow, as: :boolean %>
7
+ <%= f.input :robot_index, as: :boolean %>
8
8
  </fieldset>
@@ -1,3 +1,3 @@
1
1
  <h1>
2
- <%= t(:title_action, action: t(action_name, scope: :actions), model: base_class.model_name.human) %>
2
+ <%= acm_t(:title_action, action: acm_t(action_name, scope: :actions), model: base_class.model_name.human) %>
3
3
  </h1>
@@ -2,9 +2,9 @@
2
2
  buttons: [
3
3
  {
4
4
  icon: "angle-double-left ",
5
- label: t(:title_action, action: t(:index, scope: :actions), model: base_class.model_name.human),
5
+ label: acm_t(:title_action, action: acm_t(:index, scope: :actions), model: base_class.model_name.human),
6
6
  url: polymorphic_path(url_namespace),
7
- title: t(:title_action, action: t(:index, scope: :actions), model: base_class.model_name.human),
7
+ title: acm_t(:title_action, action: acm_t(:index, scope: :actions), model: base_class.model_name.human),
8
8
  hotkey: 'alt+b',
9
9
  dialog: false,
10
10
  if_permitted_to: [:index, @obj.class]
@@ -1,4 +1,3 @@
1
-
2
1
  <% content_for(:toolbar) do %>
3
2
  <%= render 'alchemy/admin/partials/site_select' %>
4
3
  <%= render 'language_tree_select' %>
@@ -32,6 +31,28 @@
32
31
  }
33
32
  end
34
33
 
34
+ if can?(:export_csv, base_class) and check_presence_polymorphic_path([:export_csv, :admin, base_class.to_s.demodulize.downcase.pluralize ], :get, format: :csv)
35
+ buttons << {
36
+ icon: "download",
37
+ label: t(:export_selected_data),
38
+ url: polymorphic_path([:export_csv, :admin, base_class.to_s.demodulize.downcase.pluralize],format: :csv),
39
+ title: t(:export_selected_data),
40
+ dialog: false,
41
+ if_permitted_to: [:export_csv, base_class]
42
+ }
43
+ end
44
+
45
+ if can?(:export_csv_full, base_class) and check_presence_polymorphic_path([:export_csv_full, :admin, base_class.to_s.demodulize.downcase.pluralize ], :get, format: :csv)
46
+ buttons << {
47
+ icon: "file-archive",
48
+ label: t(:export_all_data),
49
+ url: polymorphic_path([:export_csv_full, :admin, base_class.to_s.demodulize.downcase.pluralize],format: :csv),
50
+ title: t(:export_all_data),
51
+ dialog: false,
52
+ if_permitted_to: [:export_csv_full, base_class]
53
+ }
54
+ end
55
+
35
56
  %>
36
57
 
37
58
  <% toolbar(
@@ -44,7 +65,7 @@
44
65
 
45
66
  <div id="archive_all" class="resources-table-wrapper">
46
67
 
47
- <%= content_tag :h1, "#{@objects.count} #{base_class.model_name.human(count: @objects.count)}", class: 'resources-header' %>
68
+ <%= content_tag :h1, "#{@total_objects.count} #{base_class.model_name.human(count: @objects.count)}", class: 'resources-header' %>
48
69
 
49
70
 
50
71
  <%= render partial: "table" %>
@@ -2,9 +2,9 @@
2
2
  buttons: [
3
3
  {
4
4
  icon: "angle-double-left ",
5
- label: acm_t(:title_action, action: t(:index, scope: :actions), model: base_class.model_name.human),
5
+ label: acm_t(:title_action, action: acm_t(:index, scope: :actions), model: base_class.model_name.human),
6
6
  url: polymorphic_path(url_namespace),
7
- title: acm_t(:title_action, action: t(:index, scope: :actions), model: base_class.model_name.human),
7
+ title: acm_t(:title_action, action: acm_t(:index, scope: :actions), model: base_class.model_name.human),
8
8
  hotkey: 'alt+b',
9
9
  dialog: false,
10
10
  if_permitted_to: [:index, @obj.class]
@@ -3,9 +3,9 @@
3
3
 
4
4
  buttons << {
5
5
  icon: "angle-double-left ",
6
- label: acm_t(:title_action, action: t(:index, scope: :actions), model: base_class.model_name.human),
6
+ label: acm_t(:title_action, action: acm_t(:index, scope: :actions), model: base_class.model_name.human),
7
7
  url: polymorphic_path(url_namespace),
8
- title: acm_t(:title_action, action: t(:index, scope: :actions), model: base_class.model_name.human),
8
+ title: acm_t(:title_action, action: acm_t(:index, scope: :actions), model: base_class.model_name.human),
9
9
  hotkey: 'alt+b',
10
10
  dialog: false,
11
11
  if_permitted_to: [:index, @obj.class]