alchemy-custom-model 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +147 -0
- data/Rakefile +32 -0
- data/app/assets/config/alchemy_custom_model_manifest.js +3 -0
- data/app/assets/images/alchemy-custom-model/no_image.png +0 -0
- data/app/assets/javascripts/alchemy-custom-model/change_language.js +11 -0
- data/app/assets/javascripts/alchemy-custom-model/common_init.js +16 -0
- data/app/assets/javascripts/alchemy-custom-model/custom_admin_element_editor.js.coffee +25 -0
- data/app/assets/javascripts/alchemy-custom-model/custom_tiny_mce.js.coffee.erb +95 -0
- data/app/assets/javascripts/alchemy-custom-model/el_finder.js.coffee.erb +241 -0
- data/app/assets/javascripts/alchemy-custom-model/elfinder_ui_manifest.js +4 -0
- data/app/assets/javascripts/alchemy-custom-model/manifest.js +23 -0
- data/app/assets/javascripts/alchemy-custom-model/nested_attributes_sortable.js.coffee +25 -0
- data/app/assets/javascripts/alchemy-custom-model/select2filter.js +51 -0
- data/app/assets/javascripts/alchemy-custom-model/subobjects.js +98 -0
- data/app/assets/javascripts/alchemy-custom-model/total_page_elfinder.js.coffee +15 -0
- data/app/assets/stylesheets/alchemy-custom-model/custom_elfinder.css.scss +130 -0
- data/app/assets/stylesheets/alchemy-custom-model/custom_style.css.scss +228 -0
- data/app/assets/stylesheets/alchemy-custom-model/custom_tiny_mce.scss +6 -0
- data/app/assets/stylesheets/alchemy-custom-model/manifest.css +16 -0
- data/app/controllers/alchemy/custom/model/admin/base_controller.rb +189 -0
- data/app/controllers/alchemy/custom/model/admin/files_controller.rb +106 -0
- data/app/controllers/alchemy/pages_controller_decorator.rb +1 -0
- data/app/helpers/alchemy/custom/model/admin/base_helper.rb +379 -0
- data/app/helpers/alchemy/custom/model/base_helper.rb +18 -0
- data/app/helpers/alchemy/custom/model/custom_model_helper.rb +112 -0
- data/app/helpers/alchemy/pages_helper_decorator.rb +95 -0
- data/app/models/admin_override_to_param.rb +9 -0
- data/app/models/application_record.rb +9 -0
- data/app/views/alchemy/custom/model/admin/base/_buttons_tool.html.erb +16 -0
- data/app/views/alchemy/custom/model/admin/base/_gallery_item.html.erb +4 -0
- data/app/views/alchemy/custom/model/admin/base/_language_tree_select.html.erb +9 -0
- data/app/views/alchemy/custom/model/admin/base/_search_box.html.erb +19 -0
- data/app/views/alchemy/custom/model/admin/base/_seo.html.erb +8 -0
- data/app/views/alchemy/custom/model/admin/base/_table.html.erb +33 -0
- data/app/views/alchemy/custom/model/admin/base/_title.html.erb +3 -0
- data/app/views/alchemy/custom/model/admin/base/edit.html.erb +18 -0
- data/app/views/alchemy/custom/model/admin/base/index.html.erb +39 -0
- data/app/views/alchemy/custom/model/admin/base/new.html.erb +19 -0
- data/app/views/alchemy/custom/model/admin/files/error_notice.json.jbuilder +1 -0
- data/app/views/alchemy/custom/model/admin/files/ui.html.erb +13 -0
- data/config/initializers/elfinder_abilities.rb +1 -0
- data/config/locales/en.yml +11 -0
- data/config/locales/it.yml +21 -0
- data/config/routes.rb +8 -0
- data/lib/alchemy-custom-model.rb +29 -0
- data/lib/alchemy/custom/model/el_finder.rb +17 -0
- data/lib/alchemy/custom/model/el_finder/ability.rb +16 -0
- data/lib/alchemy/custom/model/el_finder/connector.rb +435 -0
- data/lib/alchemy/custom/model/el_finder/image.rb +35 -0
- data/lib/alchemy/custom/model/el_finder/path_name.rb +220 -0
- data/lib/alchemy/custom/model/el_finder/paths.rb +21 -0
- data/lib/alchemy/custom/model/el_finder/paths/active_record_reference.rb +50 -0
- data/lib/alchemy/custom/model/el_finder/paths/base.rb +298 -0
- data/lib/alchemy/custom/model/el_finder/paths/component_file.rb +59 -0
- data/lib/alchemy/custom/model/el_finder/paths/component_files.rb +34 -0
- data/lib/alchemy/custom/model/el_finder/paths/file.rb +23 -0
- data/lib/alchemy/custom/model/el_finder/paths/files.rb +25 -0
- data/lib/alchemy/custom/model/el_finder/paths/image.rb +42 -0
- data/lib/alchemy/custom/model/el_finder/paths/images.rb +31 -0
- data/lib/alchemy/custom/model/el_finder/paths/root.rb +24 -0
- data/lib/alchemy/custom/model/el_finder/volumes.rb +18 -0
- data/lib/alchemy/custom/model/el_finder/volumes/alchemy_file.rb +197 -0
- data/lib/alchemy/custom/model/el_finder/volumes/alchemy_files.rb +51 -0
- data/lib/alchemy/custom/model/el_finder/volumes/alchemy_images.rb +69 -0
- data/lib/alchemy/custom/model/el_finder/volumes/base.rb +149 -0
- data/lib/alchemy/custom/model/el_finder/volumes/component_attribute.rb +130 -0
- data/lib/alchemy/custom/model/engine.rb +40 -0
- data/lib/alchemy/custom/model/global_id_setter.rb +35 -0
- data/lib/alchemy/custom/model/model_decoration.rb +82 -0
- data/lib/alchemy/custom/model/pages_controller_dec.rb +132 -0
- data/lib/alchemy/custom/model/translation_scope.rb +18 -0
- data/lib/alchemy/custom/model/version.rb +7 -0
- data/lib/alchemy/touching_decorator.rb +12 -0
- data/lib/tasks/alchemy_custom_model_tasks.rake +41 -0
- data/vendor/elfinder/css/elfinder.full.css +5117 -0
- data/vendor/elfinder/css/elfinder.min.css +9 -0
- data/vendor/elfinder/css/theme.css +349 -0
- data/vendor/elfinder/js/elfinder.full.js +34270 -0
- data/vendor/elfinder/js/elfinder.min.js +25 -0
- metadata +194 -0
@@ -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
|