alchemy-custom-model 0.1.0

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