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.
- 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
|