alchemy-custom-model 0.1.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 (82) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +147 -0
  4. data/Rakefile +32 -0
  5. data/app/assets/config/alchemy_custom_model_manifest.js +3 -0
  6. data/app/assets/images/alchemy-custom-model/no_image.png +0 -0
  7. data/app/assets/javascripts/alchemy-custom-model/change_language.js +11 -0
  8. data/app/assets/javascripts/alchemy-custom-model/common_init.js +16 -0
  9. data/app/assets/javascripts/alchemy-custom-model/custom_admin_element_editor.js.coffee +25 -0
  10. data/app/assets/javascripts/alchemy-custom-model/custom_tiny_mce.js.coffee.erb +95 -0
  11. data/app/assets/javascripts/alchemy-custom-model/el_finder.js.coffee.erb +241 -0
  12. data/app/assets/javascripts/alchemy-custom-model/elfinder_ui_manifest.js +4 -0
  13. data/app/assets/javascripts/alchemy-custom-model/manifest.js +23 -0
  14. data/app/assets/javascripts/alchemy-custom-model/nested_attributes_sortable.js.coffee +25 -0
  15. data/app/assets/javascripts/alchemy-custom-model/select2filter.js +51 -0
  16. data/app/assets/javascripts/alchemy-custom-model/subobjects.js +98 -0
  17. data/app/assets/javascripts/alchemy-custom-model/total_page_elfinder.js.coffee +15 -0
  18. data/app/assets/stylesheets/alchemy-custom-model/custom_elfinder.css.scss +130 -0
  19. data/app/assets/stylesheets/alchemy-custom-model/custom_style.css.scss +228 -0
  20. data/app/assets/stylesheets/alchemy-custom-model/custom_tiny_mce.scss +6 -0
  21. data/app/assets/stylesheets/alchemy-custom-model/manifest.css +16 -0
  22. data/app/controllers/alchemy/custom/model/admin/base_controller.rb +189 -0
  23. data/app/controllers/alchemy/custom/model/admin/files_controller.rb +106 -0
  24. data/app/controllers/alchemy/pages_controller_decorator.rb +1 -0
  25. data/app/helpers/alchemy/custom/model/admin/base_helper.rb +379 -0
  26. data/app/helpers/alchemy/custom/model/base_helper.rb +18 -0
  27. data/app/helpers/alchemy/custom/model/custom_model_helper.rb +112 -0
  28. data/app/helpers/alchemy/pages_helper_decorator.rb +95 -0
  29. data/app/models/admin_override_to_param.rb +9 -0
  30. data/app/models/application_record.rb +9 -0
  31. data/app/views/alchemy/custom/model/admin/base/_buttons_tool.html.erb +16 -0
  32. data/app/views/alchemy/custom/model/admin/base/_gallery_item.html.erb +4 -0
  33. data/app/views/alchemy/custom/model/admin/base/_language_tree_select.html.erb +9 -0
  34. data/app/views/alchemy/custom/model/admin/base/_search_box.html.erb +19 -0
  35. data/app/views/alchemy/custom/model/admin/base/_seo.html.erb +8 -0
  36. data/app/views/alchemy/custom/model/admin/base/_table.html.erb +33 -0
  37. data/app/views/alchemy/custom/model/admin/base/_title.html.erb +3 -0
  38. data/app/views/alchemy/custom/model/admin/base/edit.html.erb +18 -0
  39. data/app/views/alchemy/custom/model/admin/base/index.html.erb +39 -0
  40. data/app/views/alchemy/custom/model/admin/base/new.html.erb +19 -0
  41. data/app/views/alchemy/custom/model/admin/files/error_notice.json.jbuilder +1 -0
  42. data/app/views/alchemy/custom/model/admin/files/ui.html.erb +13 -0
  43. data/config/initializers/elfinder_abilities.rb +1 -0
  44. data/config/locales/en.yml +11 -0
  45. data/config/locales/it.yml +21 -0
  46. data/config/routes.rb +8 -0
  47. data/lib/alchemy-custom-model.rb +29 -0
  48. data/lib/alchemy/custom/model/el_finder.rb +17 -0
  49. data/lib/alchemy/custom/model/el_finder/ability.rb +16 -0
  50. data/lib/alchemy/custom/model/el_finder/connector.rb +435 -0
  51. data/lib/alchemy/custom/model/el_finder/image.rb +35 -0
  52. data/lib/alchemy/custom/model/el_finder/path_name.rb +220 -0
  53. data/lib/alchemy/custom/model/el_finder/paths.rb +21 -0
  54. data/lib/alchemy/custom/model/el_finder/paths/active_record_reference.rb +50 -0
  55. data/lib/alchemy/custom/model/el_finder/paths/base.rb +298 -0
  56. data/lib/alchemy/custom/model/el_finder/paths/component_file.rb +59 -0
  57. data/lib/alchemy/custom/model/el_finder/paths/component_files.rb +34 -0
  58. data/lib/alchemy/custom/model/el_finder/paths/file.rb +23 -0
  59. data/lib/alchemy/custom/model/el_finder/paths/files.rb +25 -0
  60. data/lib/alchemy/custom/model/el_finder/paths/image.rb +42 -0
  61. data/lib/alchemy/custom/model/el_finder/paths/images.rb +31 -0
  62. data/lib/alchemy/custom/model/el_finder/paths/root.rb +24 -0
  63. data/lib/alchemy/custom/model/el_finder/volumes.rb +18 -0
  64. data/lib/alchemy/custom/model/el_finder/volumes/alchemy_file.rb +197 -0
  65. data/lib/alchemy/custom/model/el_finder/volumes/alchemy_files.rb +51 -0
  66. data/lib/alchemy/custom/model/el_finder/volumes/alchemy_images.rb +69 -0
  67. data/lib/alchemy/custom/model/el_finder/volumes/base.rb +149 -0
  68. data/lib/alchemy/custom/model/el_finder/volumes/component_attribute.rb +130 -0
  69. data/lib/alchemy/custom/model/engine.rb +40 -0
  70. data/lib/alchemy/custom/model/global_id_setter.rb +35 -0
  71. data/lib/alchemy/custom/model/model_decoration.rb +82 -0
  72. data/lib/alchemy/custom/model/pages_controller_dec.rb +132 -0
  73. data/lib/alchemy/custom/model/translation_scope.rb +18 -0
  74. data/lib/alchemy/custom/model/version.rb +7 -0
  75. data/lib/alchemy/touching_decorator.rb +12 -0
  76. data/lib/tasks/alchemy_custom_model_tasks.rake +41 -0
  77. data/vendor/elfinder/css/elfinder.full.css +5117 -0
  78. data/vendor/elfinder/css/elfinder.min.css +9 -0
  79. data/vendor/elfinder/css/theme.css +349 -0
  80. data/vendor/elfinder/js/elfinder.full.js +34270 -0
  81. data/vendor/elfinder/js/elfinder.min.js +25 -0
  82. metadata +194 -0
@@ -0,0 +1,6 @@
1
+ .base_form_container {
2
+ .tinymce_container {
3
+ float: right;
4
+ width: 65%;
5
+ }
6
+ }
@@ -0,0 +1,16 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require "alchemy-custom-model/custom_elfinder"
14
+ *= require "alchemy-custom-model/custom_tiny_mce"
15
+ *= require "alchemy-custom-model/custom_style"
16
+ */
@@ -0,0 +1,189 @@
1
+ module Alchemy::Custom::Model
2
+ module Admin
3
+ class BaseController < Alchemy::Custom::Model.admin_controller_class
4
+
5
+ before_action :authorize_resource
6
+ before_action :clean_slug, only: [:create, :update]
7
+ before_action :set_language, unless: -> {params[:language_id].nil?}
8
+ before_action :load_object, except: :index
9
+
10
+ helper_method :base_class
11
+ helper_method :table_columns
12
+ helper_method :url_namespace
13
+
14
+ helper Alchemy::Custom::Model::BaseHelper
15
+
16
+
17
+ def index
18
+ @query = base_class.ransack(params[:q])
19
+ @objects = @query.result(distinct: true)
20
+ @objects = @objects.accessible_by(current_ability).only_current_language
21
+ @objects = @objects.page(params[:page]).
22
+ per(params[:per_page] ||
23
+ (base_class::DEFAULT_PER_PAGE if base_class.const_defined? :DEFAULT_PER_PAGE) ||
24
+ 25)
25
+ instance_variable_set "@#{base_class.name.demodulize.underscore.downcase.pluralize}", @objects
26
+ end
27
+
28
+ def new
29
+
30
+ end
31
+
32
+ def edit
33
+
34
+ end
35
+
36
+ def update
37
+ if @obj.update_attributes(clean_params)
38
+ after_successful_update
39
+ else
40
+ atfer_unsuccessful_update
41
+ end
42
+ end
43
+
44
+ def destroy
45
+ if @obj.destroy
46
+ after_successful_destroy
47
+ else
48
+ after_unsuccessful_destroy
49
+ end
50
+ end
51
+
52
+ def create
53
+ if @obj.update_attributes(clean_params)
54
+ after_successful_create
55
+ else
56
+ after_unsuccessful_create
57
+ end
58
+
59
+ end
60
+
61
+
62
+ class << self
63
+
64
+ mattr_accessor :parent_model_name, :parent_klass, :parent_find_method
65
+
66
+ def belongs_to(model_name, options = {})
67
+ prepend_before_action :load_parent
68
+ const_model_klass = options[:model_klass].to_s.constantize unless options[:model_klass].nil?
69
+ self.parent_model_name = model_name.to_s
70
+ self.parent_klass = const_model_klass || self.parent_model_name.to_s.classify.constantize
71
+ self.parent_find_method = options[:find_by].to_s || "id"
72
+ end
73
+ end
74
+
75
+
76
+ private
77
+
78
+ def table_columns
79
+ base_class.columns.collect(&:name).collect {|c| c.to_sym}.reject do |c|
80
+ [
81
+ :created_at,
82
+ :updated_at,
83
+ :id,
84
+ :language_id,
85
+ :meta_keywords,
86
+ :meta_description,
87
+ :meta_title,
88
+ :robot_follow,
89
+ :robot_index
90
+ ].include? c
91
+ end
92
+ end
93
+
94
+ def base_class
95
+ raise '-- Override Method base_class'
96
+ end
97
+
98
+ def url_namespace(obj=base_class)
99
+ [:admin, obj]
100
+ end
101
+
102
+ def load_object
103
+ if params[:id]
104
+ if base_class.respond_to? :friendly
105
+ @obj = base_class.friendly.find(params[:id])
106
+ else
107
+ @obj = base_class.find(params[:id])
108
+ end
109
+ else
110
+ @obj = base_class.new
111
+ end
112
+ instance_variable_set("@#{base_class.name.demodulize.underscore.downcase.singularize}", @obj)
113
+ end
114
+
115
+ def resource_instance_variable
116
+ @obj
117
+ end
118
+
119
+
120
+ def authorize_resource
121
+ authorize!(action_name.to_sym, @obj || base_class)
122
+ end
123
+
124
+ def permitted_attributes
125
+ base_class.attribute_names.collect {|c| c.to_sym}
126
+ end
127
+
128
+ def clean_params
129
+ dati = params.required(base_class.name.underscore.gsub('/', '_').to_sym).permit(permitted_attributes)
130
+ ::Rails.logger.info {"Permitted Attributes: #{permitted_attributes.inspect}"}
131
+ ::Rails.logger.info {"Parametri puliti: #{dati.inspect}"}
132
+ dati
133
+ end
134
+
135
+ def clean_slug
136
+ slug = params[base_class.name.underscore.gsub('/', '_').to_sym][:slug]
137
+ if slug.blank?
138
+ params[base_class.name.underscore.gsub('/', '_').to_sym].delete(:slug)
139
+ end
140
+ end
141
+
142
+ def after_successful_destroy
143
+ redirect_to polymorphic_path(url_namespace), notice: t(:record_succesfully_destroy, model: base_class.model_name.human)
144
+ end
145
+
146
+ def after_unsuccessful_destroy
147
+ redirect_to polymorphic_path(url_namespace), error: t(:record_unsuccesfully_destroy, model: base_class.model_name.human)
148
+ end
149
+
150
+ def after_successful_update
151
+ redirect_to polymorphic_path(url_namespace), notice: t(:record_succesfully_update, model: base_class.model_name.human)
152
+ end
153
+
154
+ def atfer_unsuccessful_update
155
+ render :edit
156
+ end
157
+
158
+ def after_successful_create
159
+ redirect_to polymorphic_path(url_namespace), notice: t(:record_succesfully_create, model: base_class.model_name.human)
160
+ end
161
+
162
+ def after_unsuccessful_create
163
+ render :new
164
+ end
165
+
166
+
167
+ def set_language
168
+ set_alchemy_language(params[:language_id])
169
+ end
170
+
171
+
172
+ def load_parent
173
+ unless self.class.parent_model_name.blank?
174
+ @parent = self.class.parent_klass.
175
+ find_by("#{self.class.parent_find_method.to_s}": params["#{parent_model_name_demodulized}_id"])
176
+
177
+ instance_variable_set("@#{parent_model_name_demodulized}", @parent)
178
+ end
179
+ end
180
+
181
+ def parent_model_name_demodulized
182
+ self.class.parent_model_name.
183
+ classify.demodulize.underscore
184
+ end
185
+
186
+
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,106 @@
1
+ module Alchemy::Custom::Model
2
+ module Admin
3
+ class FilesController < Alchemy::Custom::Model.admin_controller_class
4
+
5
+ skip_before_action :verify_authenticity_token, :only => ['elfinder']
6
+
7
+ def elfinder
8
+ authorize! :usage, Alchemy::Custom::Model::ElFinder
9
+
10
+ h, r, f = connector.run(params)
11
+
12
+ headers.merge!(h)
13
+
14
+ if f.blank?
15
+ render (r.empty? ? {:nothing => true} : {:plain => r.to_json}), :layout => false
16
+ else
17
+ send_file f[:path], disposition: :inline
18
+ end
19
+
20
+
21
+ end
22
+
23
+ def ui
24
+ @volumes = params[:volumes]
25
+ authorize! :ui_usage, Alchemy::Custom::Model::ElFinder
26
+ render layout: false
27
+ end
28
+
29
+ private
30
+
31
+ def connector
32
+
33
+
34
+ volumi = []
35
+
36
+ if params[:volumes].blank?
37
+ volumi << ElFinder::Volumes::AlchemyFile.new
38
+ else
39
+
40
+ volumes = params[:volumes]
41
+ volumes = volumes.split(',') if volumes.is_a? String
42
+
43
+ volumes_cfgs = {}
44
+ if params[:volumes_cfgs]
45
+ volumes_cfgs = ActiveSupport::HashWithIndifferentAccess.new(ActiveSupport::JSON.decode(Base64.strict_decode64(params[:volumes_cfgs])))
46
+ Rails.logger.info {"CONFIGURAZIONE_VOLUMI: #{volumes_cfgs.inspect}"}
47
+ end
48
+
49
+
50
+ volumes.each do |v|
51
+
52
+ if volumes_cfgs.key?(v)
53
+
54
+ cfgs = volumes_cfgs[v]
55
+
56
+ volumi << ElFinder::Volumes.const_get(cfgs.delete(:volume)).new(cfgs)
57
+ else
58
+ volumi << ElFinder::Volumes.const_get(v).new
59
+ end
60
+
61
+ end
62
+ end
63
+
64
+
65
+ ElFinder::Connector.new(
66
+ :root => '/alchemy_library', #File.join(Rails.public_path, 'public'),
67
+ # :url => '/system/elfinder',
68
+ # :perms => {
69
+ # /^(Welcome|README)$/ => {:read => true, :write => false, :rm => false},
70
+ # '.' => {:read => true, :write => false, :rm => false}, # '.' is the proper way to specify the home/root directory.
71
+ # /^test$/ => {:read => true, :write => true, :rm => false},
72
+ # 'logo.png' => {:read => true},
73
+ # /\.png$/ => {:read => false} # This will cause 'logo.png' to be unreadable.
74
+ # # Permissions err on the safe side. Once false, always false.
75
+ # },
76
+ # :extractors => {
77
+ # 'application/zip' => ['unzip', '-qq', '-o'], # Each argument will be shellescaped (also true for archivers)
78
+ # 'application/x-gzip' => ['tar', '-xzf'],
79
+ # },
80
+ # :archivers => {
81
+ # 'application/zip' => ['.zip', 'zip', '-qr9'], # Note first argument is archive extension
82
+ # 'application/x-gzip' => ['.tgz', 'tar', '-czf'],
83
+ # },
84
+ # :tree_sub_folders => true,
85
+ #adds {Rails.root}/public/uploads as "root" volume, named "uploads" in the GUI
86
+ :volumes => volumi,
87
+ #[{:id => "root", :name => "uploads", :root => File.join(Rails.root, 'public', 'uploads'), :url => "files/"}],
88
+ :mime_handler => ::ElFinder::MimeType,
89
+ :image_handler => ElFinder::Image,
90
+ :original_filename_method => lambda {|file| file.original_filename.respond_to?(:force_encoding) ? file.original_filename.force_encoding('utf-8') : file.original_filename},
91
+ :disabled_commands => ['mkfile'],
92
+ :allow_dot_files => true,
93
+ :upload_max_size => '50M',
94
+ # :upload_file_mode => 0644,
95
+ :home => 'Home',
96
+ :default_perms => {:read => true, :write => true, :rm => true, :hidden => false},
97
+ :thumbs => false,
98
+ :thumbs_directory => '.thumbs',
99
+ :thumbs_size => 48,
100
+ :thumbs_at_once => 5,
101
+ )
102
+ end
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1 @@
1
+ Alchemy::PagesController.include Alchemy::Custom::Model::PagesControllerDec
@@ -0,0 +1,379 @@
1
+ module Alchemy::Custom::Model::Admin::BaseHelper
2
+
3
+
4
+ def base_form_container
5
+ content_tag :div, class: "base_form_container #{controller_name}" do
6
+ yield
7
+ end
8
+ end
9
+
10
+ def rich_text_editor(form, field)
11
+
12
+ editor_idenfier = "#{field}_#{form.object_id}"
13
+
14
+ bf = ActiveSupport::SafeBuffer.new
15
+ bf << form.input(field) do
16
+ content_tag(:div, class: 'tinymce_container') do
17
+ form.text_area field, class: 'has_tinymce', id: "tinymce_#{editor_idenfier}"
18
+ end
19
+ end
20
+
21
+ bf << content_tag(:script, :type => "text/javascript") do
22
+ raw "(function(){
23
+ CustomTinyMce.initEditor('#{editor_idenfier}')
24
+ })();
25
+ "
26
+ end
27
+
28
+ bf
29
+
30
+
31
+ end
32
+
33
+
34
+ def single_image_input(form, field)
35
+
36
+ form.input(field) do
37
+ content_tag(:div, class: "elfinder_picture_thumbnail") do
38
+ bf = ActiveSupport::SafeBuffer.new
39
+
40
+ component_id = SecureRandom.hex(10)
41
+ component_id_image = "#{component_id}_image"
42
+
43
+ ref_id = nil
44
+
45
+ unless form.object.send(field).blank?
46
+ ref_id = form.object.send(field).to_signed_global_id.to_s
47
+ end
48
+
49
+ bf << form.hidden_field(field, id: component_id, value: ref_id)
50
+
51
+ image_path = no_image_path = image_url("alchemy-custom-model/no_image.png")
52
+
53
+ image_path = form.object.send(field).image_file.thumb("100x100#").url if form.object.send(field) and form.object.send(field).image_file_stored?
54
+
55
+ bf << content_tag(:div, image_tag(image_path, id: component_id_image, class: "picture_image"))
56
+
57
+ bf << content_tag(:div, class: "edit_images_bottom") do
58
+
59
+ bf2 = ActiveSupport::SafeBuffer.new
60
+
61
+ bf2 << link_to("#", class: 'open_el_finder',
62
+ title: t("elfinder.edit_image_button"),
63
+ data: {
64
+ "elfinder-mode": 'single_selection',
65
+ "elfinder-target": "##{component_id}",
66
+ "elfinder-thumb-target": "##{component_id_image}",
67
+ "elfinder-volumes": 'AlchemyImages'
68
+ }) do
69
+ fa_icon("file-image")
70
+ end
71
+
72
+ bf2 << link_to("#", class: 'clear_selection',
73
+ title: t("elfinder.clear_image_button"),
74
+ data: {
75
+ "clearfield-target": "##{component_id}",
76
+ "clearfield-thumb-target": "##{component_id_image}",
77
+ "clearfield-thumb-target-replace": no_image_path
78
+ }) do
79
+ fa_icon("times")
80
+ end
81
+
82
+ bf2
83
+ end
84
+
85
+ bf
86
+
87
+ end
88
+ end
89
+
90
+
91
+ end
92
+
93
+ ##
94
+ # rimpiazzo helper per icone
95
+ def fa_icon(icon, title: nil)
96
+ content_tag(:i, nil, class: "fas fa-#{icon} fa-lg fa-fw", title: title)
97
+ end
98
+
99
+
100
+ def mime2class(mimeType)
101
+ prefix = 'elfinder-cwd-icon-'
102
+ mime = mimeType.downcase
103
+ # isText = this.textMimes[mime]
104
+ #
105
+ mime = mime.split('/')
106
+ # if (isText) {
107
+ # mime[0] += ' ' + prefix + 'text';
108
+ # }
109
+
110
+ prefix + mime[0] + (mime[1] ? ' ' + prefix + mime[1].gsub(/(\.|\+)/, '-') : '')
111
+ end
112
+
113
+
114
+ def single_attachment_input(form, field)
115
+ form.input(field) do
116
+ content_tag(:div, class: "elfinder_attachment") do
117
+ bf = ActiveSupport::SafeBuffer.new
118
+
119
+ component_id = SecureRandom.hex(10)
120
+
121
+ ref_id = nil
122
+ mime_class = ''
123
+
124
+ unless form.object.send(field).blank?
125
+ ref_id = form.object.send(field).to_signed_global_id.to_s
126
+ mime_class = "elfinder-cwd-icon #{mime2class(form.object.send(field).file_mime_type)}"
127
+ end
128
+
129
+ bf << form.hidden_field(field, id: component_id, value: ref_id)
130
+
131
+ id_icone = "#{component_id}_mime_icon"
132
+
133
+ bf << content_tag(:div, class: 'container_icon_container') do
134
+ content_tag(:div, nil, id: id_icone,
135
+ class: mime_class)
136
+ end
137
+
138
+ bf << content_tag(:div, class: "edit_file_bottom") do
139
+
140
+ bf2 = ActiveSupport::SafeBuffer.new
141
+
142
+ bf2 << link_to("#", class: 'open_el_finder',
143
+ title: t("elfinder.edit_attachment_button"),
144
+ data: {
145
+ "elfinder-mode": 'single_selection',
146
+ "elfinder-target": "##{component_id}",
147
+ "elfinder-mime_icon_updater": "##{id_icone}",
148
+ "elfinder-volumes": 'AlchemyFiles'
149
+ }) do
150
+ fa_icon("file")
151
+ end
152
+
153
+ bf2 << link_to("#", class: 'clear_selection',
154
+ title: t("elfinder.clear_attachment_button"),
155
+ data: {
156
+ "clearfield-target": "##{component_id}",
157
+ "clearfield-icon": "##{id_icone}"
158
+ }) do
159
+ fa_icon("times")
160
+ end
161
+
162
+ bf2
163
+ end
164
+
165
+ bf
166
+
167
+ end
168
+ end
169
+ end
170
+
171
+
172
+ def base_container
173
+ content_tag :div, class: "base_container #{controller_name}" do
174
+ yield
175
+ end
176
+ end
177
+
178
+ def render_obj(obj, field)
179
+ obj.send field
180
+ end
181
+
182
+
183
+
184
+ ##
185
+ # Costruisce il necessario per la generazione della struttura della gallery e per selezione ed upload immagini
186
+ #
187
+ # @param [FormBuilder] form
188
+ # @param [Symbol] field
189
+ # @param [String] partial_url url da richiamare ogni volta che avviene una modifica nell'elenco dei files
190
+ # della gallery
191
+ # @param [String] partial_identifier selettore css da utilizzare per fare il replace e la ricerca del contenuto
192
+ # trovato con url
193
+ # @param [Array] tags Array di stringhe identificanti i tags da aggiungere ad ogni immagine caricata
194
+ # direttamente nel volume legato a questo componente
195
+ #
196
+ def gallery_input(form, field, partial_url:, partial_identifier:, tags: [])
197
+
198
+ return '' unless form.object.persisted?
199
+
200
+
201
+ obj_cls = form.object.class
202
+ hint_helper = ''
203
+ chiave_i18n = "#{obj_cls.i18n_scope}.attributes.#{obj_cls.model_name.i18n_key}.#{field}_hint"
204
+ hint_helper = hint_with_tooltip(t(chiave_i18n), icon: 'question-circle') if I18n.exists?(chiave_i18n)
205
+
206
+ form.input(field, label: obj_cls.human_attribute_name(field).html_safe + hint_helper) do
207
+ content_tag(:div, class: 'elfinder_picture_gallery') do
208
+ bf2 = ActiveSupport::SafeBuffer.new
209
+
210
+ container_images = SecureRandom.hex
211
+
212
+ bf2 << content_tag(:div, class: 'blk_container_immagini', id: container_images) do
213
+ bf = ActiveSupport::SafeBuffer.new
214
+
215
+ component_id = SecureRandom.hex(10)
216
+
217
+ bf << form.fields_for(field) do |join_record_form|
218
+ render(layout: 'gallery_item', locals: {picture: join_record_form.object.picture}) do
219
+
220
+ join_record_form.hidden_field :position, class: 'gallery_position_counter'
221
+
222
+ end
223
+ end
224
+
225
+ bf << content_tag(:div, class: 'gallery_item_blk') do
226
+ link_to("#", class: 'open_el_finder', data: {
227
+ "elfinder-mode": 'multiple_selection',
228
+ "elfinder-target_upgrader": partial_url,
229
+ "elfinder-target": partial_identifier,
230
+ "elfinder-volumes": 'AlchemyImages,GalleryVolume',
231
+ "elfinder-volumes_cfgs": Base64.strict_encode64({
232
+ "GalleryVolume": {
233
+ volume: 'ComponentAttribute',
234
+ attribute: field,
235
+ object: form.object.to_signed_global_id.to_s,
236
+ file_link_ref: 'picture',
237
+ tags: tags
238
+ }
239
+ }.to_json)
240
+ }) do
241
+ fa_icon("images")
242
+ end
243
+ end
244
+
245
+
246
+ bf
247
+
248
+ end
249
+
250
+ bf2 << content_tag(:script, :type => "text/javascript") do
251
+ raw "(function(){
252
+ $('##{container_images}').nested_attributes_sortable({field:'.gallery_position_counter'});
253
+ })();
254
+ "
255
+ end
256
+
257
+ bf2
258
+ end
259
+ end
260
+
261
+
262
+ end
263
+
264
+
265
+ # @param [Symbol] label per la form
266
+ # @param [FormBuilder] form
267
+ # @param [Symbol] field identifica la relazione
268
+ # @param [Object] to_load TODO documentare
269
+ # @param [Object] url_partial url da dove caricare il partial da dove arriva un nuovo blocco html contenente questo subelemento
270
+ # @param [Object] active_record_modifier Proc chiamata durante l'esecuzione della query per la selezione degli elementi,
271
+ # sovrascrivere e ritornare un ActiveRecord::Relation
272
+ def subobject(label, form, field, to_load:, url_partial:, active_record_modifier: ->(relation) {relation})
273
+
274
+ ui_identify = "subobjects_container_#{SecureRandom.hex}"
275
+
276
+ interface = ActiveSupport::SafeBuffer.new
277
+ interface = content_tag(:fieldset, class: "subobjects #{ui_identify}") do
278
+ sb = ActiveSupport::SafeBuffer.new
279
+
280
+ sb << content_tag(:legend, label)
281
+ sb << content_tag(:div, class: "sub_objects_container sub_object_#{field}") do
282
+ sub_obj = ActiveSupport::SafeBuffer.new
283
+
284
+ active_record_modifier.call(form.object.send(field)).each_with_index do |subo, index|
285
+
286
+ sub_obj << form.simple_fields_for(field, subo, child_index: subo.new_record? ? Time.now.getutc.strftime("%9N") : index) do |subform|
287
+
288
+ form_attrs = subform.object.attributes.reject do |attr, val|
289
+ attr == form.object.class.reflect_on_association(field).foreign_key
290
+ end
291
+ is_sample = form_attrs.all? {|attr, val| val.blank?}
292
+
293
+ content_tag(:div, id: "#{subform.object.class.name.demodulize.underscore}_#{subform.object.id}", class: "subobject_row row_#{field.to_s.singularize} #{"sample" if is_sample}") do
294
+
295
+ form_html = ActiveSupport::SafeBuffer.new
296
+
297
+
298
+ form_html << content_tag(:div, class: "buttons toolbar_button") do
299
+ button_bar = ActiveSupport::SafeBuffer.new
300
+ button_bar << content_tag(:div, class: "button_with_label maximize") do
301
+ link_to "#", class: "icon_button" do
302
+ fa_icon "window-maximize"
303
+ end
304
+ end
305
+
306
+ button_bar << content_tag(:div, class: "button_with_label minimize") do
307
+ link_to "#", class: "icon_button" do
308
+ fa_icon "window-minimize"
309
+ end
310
+ end
311
+
312
+ button_bar << content_tag(:div, class: "button_with_label remove") do
313
+ content_tag(:span, class: "icon_button") do
314
+ icon_button = ActiveSupport::SafeBuffer.new
315
+ icon_button << fa_icon("trash", title: t(:remove))
316
+ icon_button << subform.input(:_destroy, as: :hidden, input_html: {class: "destroy"})
317
+ icon_button
318
+ end
319
+
320
+ end
321
+
322
+
323
+ button_bar
324
+ end
325
+ form_html << content_tag(:div, class: "fields") do
326
+ yield subform
327
+ end
328
+
329
+
330
+ form_html
331
+ end
332
+ end
333
+
334
+
335
+ end
336
+
337
+ #sub_obj << content_for(:"sample_#{field}")
338
+ sub_obj
339
+ end
340
+ sb << content_tag(:div, class: "buttons") do
341
+ buttons = ActiveSupport::SafeBuffer.new
342
+ buttons << button_tag(type: "button", class: "minimize_all", title: acm_t(:minimize_all, scope: 'sub_objects')) do
343
+ fa_icon("window-minimize")
344
+ end
345
+ buttons << button_tag(type: "button", class: "maximize_all", title: acm_t(:maxzimize_all, scope: 'sub_objects')) do
346
+ fa_icon("window-maximize")
347
+ end
348
+ buttons << button_tag(type: "button", class: "add", title: acm_t(:title_add, scope: 'sub_objects'), data: {to_load: to_load, url: url_partial}) do
349
+ fa_icon("plus")
350
+ end
351
+ buttons
352
+ end
353
+ sb
354
+ end
355
+
356
+
357
+ interface << content_tag(:script, :type => "text/javascript") do
358
+ raw "(function(){
359
+ $('.#{ui_identify}').subobjects();
360
+ })();
361
+ "
362
+ end
363
+
364
+ interface
365
+
366
+ end
367
+
368
+
369
+ def check_presence_polymorphic_path(record_or_hash_or_array, options = {})
370
+ begin
371
+ polymorphic_path record_or_hash_or_array, options
372
+ true
373
+ rescue NoMethodError
374
+ false
375
+ end
376
+ end
377
+
378
+
379
+ end