alchemy-custom-model 2.0.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
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]