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,51 @@
1
+ module Alchemy::Custom::Model::ElFinder
2
+ module Volumes
3
+ class AlchemyFiles < AlchemyFile
4
+
5
+ def initialize(options = {root: '/files', name: 'Alchemy Library - Files', id: 'alchemy_library_files', url: '/'})
6
+ super
7
+ end
8
+
9
+ def files(target = '.')
10
+ super(root_path)
11
+ end
12
+
13
+ def decode(hash)
14
+ super do |path|
15
+ Paths::File.new(@root, path, volume: self)
16
+ end
17
+ end
18
+
19
+ def upload(target, upload)
20
+ super do |file|
21
+ f = ::Alchemy::Attachment.create(
22
+ file: file
23
+ )
24
+ root_path.build_file_path(f)
25
+ end
26
+ end
27
+
28
+ def search(type:, q:)
29
+
30
+ super do
31
+ search_query_build(klass: ::Alchemy::Attachment, type: type, q: q, mime_attribute: :file_mime_type)
32
+ end
33
+
34
+ end
35
+
36
+ def disabled_commands
37
+
38
+ super + ['rm']
39
+
40
+ end
41
+
42
+ private
43
+
44
+ def root_path
45
+ Paths::Files.new(@root, '.', volume: self)
46
+ end
47
+
48
+ end
49
+ end
50
+ end
51
+
@@ -0,0 +1,69 @@
1
+ module Alchemy::Custom::Model::ElFinder
2
+ module Volumes
3
+ class AlchemyImages < AlchemyFile
4
+
5
+ def initialize(options = {root: '/images', name: acm_t("volume",scope:'elfinder.alchemy_images'), id: 'alchemy_library_images', url: '/'})
6
+ super
7
+ end
8
+
9
+ def files(target = '.')
10
+ super(root_path)
11
+ end
12
+
13
+ def decode(hash)
14
+ super do |path|
15
+ Paths::Image.new(@root, path, volume: self)
16
+ end
17
+ end
18
+
19
+ def upload(target, upload)
20
+ super do |file|
21
+ img = ::Alchemy::Picture.new(
22
+ image_file: file
23
+ )
24
+ img.name = img.humanized_name
25
+ img.save!
26
+ root_path.build_file_path(img)
27
+ end
28
+ end
29
+
30
+ def search(type:, q:)
31
+
32
+ super do
33
+ search_query_build(klass: ::Alchemy::Picture, type: type, q: q, mime_attribute: :file_mime_type)
34
+ end
35
+
36
+ end
37
+
38
+ def disabled_commands
39
+
40
+ super + ['rm']
41
+
42
+ end
43
+
44
+ def duplicate(t)
45
+
46
+ new_path = Rails.root.join('tmp', "copy_#{File.basename(t.name)}")
47
+
48
+ ::FileUtils.cp(t.file.path, new_path)
49
+
50
+ img = ::Alchemy::Picture.new(
51
+ image_file: new_path
52
+ )
53
+ img.name = img.humanized_name
54
+ img.save
55
+ root_path.build_file_path(img)
56
+ end
57
+
58
+ def duplicable?(target)
59
+ true
60
+ end
61
+
62
+
63
+ def root_path
64
+ Paths::Images.new(@root, '.', volume: self)
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,149 @@
1
+ module Alchemy::Custom::Model
2
+ module ElFinder
3
+ module Volumes
4
+ class Base
5
+
6
+ include TranslationScope
7
+
8
+ attr_reader :id, :name, :root, :url
9
+
10
+ def initialize(options)
11
+ [:id, :name, :root, :url].each do |opt|
12
+ raise(ArgumentError, "Missing required #{opt} option") unless options.key?(opt)
13
+ end
14
+
15
+ @id = options[:id]
16
+ @name = options[:name]
17
+ @root = options[:root]
18
+ @url = options[:url]
19
+
20
+ # @options = {
21
+ # upload_file_mode: 0644,
22
+ # original_filename_method: lambda {|file| file.original_filename.respond_to?(:force_encoding) ? file.original_filename.force_encoding('utf-8') : file.original_filename}
23
+ # }
24
+ end
25
+
26
+ def contains?(hash)
27
+ hash.start_with?("#{@id}_")
28
+ end
29
+
30
+ def cwd(target = '.')
31
+ # {
32
+ # "name" : "Images", // (String) name of file/dir. Required
33
+ # "hash" : "l0_SW1hZ2Vz", // (String) hash of current file/dir path, first symbol must be letter, symbols before _underline_ - volume id, Required.
34
+ # "phash" : "l0_Lw", // (String) hash of parent directory. Required except roots dirs.
35
+ # "mime" : "directory", // (String) mime type. Required.
36
+ # "ts" : 1334163643, // (Number) file modification time in unix timestamp. Required.
37
+ # "date" : "30 Jan 2010 14:25", // (String) last modification time (mime). Depricated but yet supported. Use ts instead.
38
+ # "size" : 12345, // (Number) file size in bytes
39
+ # "dirs" : 1, // (Number) Only for directories. Marks if directory has child directories inside it. 0 (or not set) - no, 1 - yes. Do not need to calculate amount.
40
+ # "read" : 1, // (Number) is readable
41
+ # "write" : 1, // (Number) is writable
42
+ # "locked" : 0, // (Number) is file locked. If locked that object cannot be deleted and renamed
43
+ # "tmb" : 'bac0d45b625f8d4633435ffbd52ca495.png' // (String) Only for images. Thumbnail file name, if file do not have thumbnail yet, but it can be generated than it must have value "1"
44
+ # "alias" : "files/images", // (String) For symlinks only. Symlink target path.
45
+ # "thash" : "l1_c2NhbnMy", // (String) For symlinks only. Symlink target hash.
46
+ # "dim" : "640x480" // (String) For images - file dimensions. Optionally.
47
+ # "volumeid" : "l1_" // (String) Volume id. For root dir only.
48
+ # }
49
+ # {
50
+ # name: @name,
51
+ # hash: encode('.'),
52
+ # mime: 'directory',
53
+ # ts: File.mtime(@root).to_i,
54
+ # size: 0,
55
+ # dirs: 0,
56
+ # read: 1,
57
+ # write: 1,
58
+ # locked: 0,
59
+ # volumeid: "#{@id}_"
60
+ # }
61
+ path_info(PathName.new(@root, target))
62
+ end
63
+
64
+ # def path_info(target)
65
+ # is_dir = File.directory?(target.realpath)
66
+ # mime = is_dir ? 'directory' : ElFinder::MimeType.for(target.realpath)
67
+ # name = @name if target.is_root?
68
+ # name ||= target.basename.to_s
69
+ #
70
+ # dirs = 0
71
+ # if is_dir
72
+ # # check if has sub directories
73
+ # dirs = 1 if Dir[File.join(target.realpath, '*/')].count > 0
74
+ # end
75
+ #
76
+ # size = 0
77
+ # unless is_dir
78
+ # size = File.size(target.realpath)
79
+ # end
80
+ #
81
+ # result = {
82
+ # name: name,
83
+ # hash: encode(target.path.to_s),
84
+ # mime: mime,
85
+ # ts: File.mtime(target.realpath).to_i,
86
+ # size: size,
87
+ # dirs: dirs,
88
+ # read: 1,
89
+ # write: 1,
90
+ # locked: 0
91
+ # }
92
+ # if target.is_root?
93
+ # result[:volumeid] = "#{@id}_"
94
+ # else
95
+ # result[:phash] = encode(target.dirname.path.to_s)
96
+ # end
97
+ #
98
+ # result
99
+ # end
100
+
101
+
102
+ def decode(hash)
103
+ hash = hash.slice(("#{@id}_".length)..-1) if hash.start_with?("#{@id}_")
104
+ hash = hash.tr('-_.', '+/=')
105
+ # restore missing '='
106
+ len = hash.length % 4
107
+ hash += '==' if len == 1 or len == 2
108
+ hash += '=' if len == 3
109
+ path = Base64.strict_decode64(hash)
110
+
111
+ if block_given?
112
+ yield path
113
+ else
114
+ PathName.new(@root, path)
115
+ end
116
+
117
+ end
118
+
119
+ def encode(path)
120
+ # creates hash for the path
121
+ # path = ElFinder::Pathname.new(@root, path).path.to_s
122
+ hash = Base64.strict_encode64(path)
123
+ hash.tr!('+/=', '-_.')
124
+ hash.gsub!(/\.+\Z/, '')
125
+ "#{@id}_#{hash}"
126
+ end
127
+
128
+ # def files(target = '.')
129
+ # target = ElFinder::Pathname.new(@root, target)
130
+ # files = []
131
+ # # files = target.children.map {|p| path_info(p)}
132
+ # files << cwd(target)
133
+ # files
134
+ # end
135
+
136
+ def pathname(target)
137
+ raise "Absolute Path for file"
138
+ end
139
+
140
+ ##
141
+ # Elenco comandi disabilitati
142
+ def disabled_commands
143
+ []
144
+ end
145
+
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,130 @@
1
+ module Alchemy::Custom::Model::ElFinder
2
+ module Volumes
3
+ class ComponentAttribute < AlchemyFile
4
+
5
+ attr_accessor :record, :attribute, :file_link_ref, :tags
6
+
7
+ ##
8
+ # Elenco opzioni da utilizzare per la configurazione
9
+ # - attribute = relazione dell'oggetto a cui si riferisce il collegamento del volume (la join table per esempio)
10
+ # - object = oggetto identificato con un global_id signed
11
+ # - file_link_ref = rispetto ad un'istanza della relazione come fare a trovare il valore del record alchemy(Picture o Attachment),
12
+ # nel caso avessimo più metodi da chiamare possiamo spezzarlo con il . fra un metodo e l'altro
13
+ # il programma dovrà spezzare per il . e usare dig per chiamare i valori definitivi
14
+ # - tags = Array di stringhe per i tag da associare direttamente ai files caricati
15
+ def initialize(opts = {})
16
+
17
+ self.record = GlobalID::Locator.locate_signed opts.delete(:object)
18
+ self.attribute = opts.delete(:attribute)
19
+ self.file_link_ref = opts.delete(:file_link_ref)
20
+ self.tags = opts.delete(:tags) {[]}
21
+
22
+ identificativo_volume = "component_#{self.attribute}" #"_#{record.id}"
23
+
24
+ # identificativo_volume='test_semplice_nome'
25
+
26
+ # unless self.record.send(self.attribute).klass.new.respond_to?(:alchemy_file_instance)
27
+ # raise "Attenzione, non è stata impostata la relazione per collegare la join table con l'elemento il record di alchemy [:alchemy_file_instance]"
28
+ # end
29
+
30
+ super({root: "/#{identificativo_volume}", name: 'Elementi associati', id: "#{identificativo_volume}", url: '/'})
31
+ end
32
+
33
+ def files(target = '.')
34
+ super(root_path)
35
+ end
36
+
37
+ def root_path
38
+ Paths::ComponentFiles.new(@root, '.', volume: self)
39
+ end
40
+
41
+ def copy(src)
42
+ new_rec = associate_record_to_active_instance(src.active_record_instance)
43
+ root_path.build_file_path(new_rec)
44
+ end
45
+
46
+ def decode(hash)
47
+ super do |path|
48
+ Paths::ComponentFile.new(@root, path, volume: self)
49
+ end
50
+ end
51
+
52
+ def upload(target, upload)
53
+ super do |file|
54
+
55
+ if remote_alchemy_relation == ::Alchemy::Picture
56
+ img = ::Alchemy::Picture.new(
57
+ image_file: file
58
+ )
59
+ img.name = img.humanized_name
60
+ img.save
61
+
62
+ #lego l'immagine ora al prodotto
63
+ new_rec = associate_record_to_active_instance(img)
64
+
65
+ root_path.build_file_path(new_rec)
66
+ else
67
+ raise "TO override"
68
+ end
69
+ end
70
+ end
71
+
72
+
73
+ ##
74
+ # Indica l'oggetto finale a cui viene legata la join table del componente
75
+ def remote_alchemy_relation
76
+ attribute_class.reflect_on_association(:alchemy_file_instance).klass
77
+ end
78
+
79
+ def attribute_class
80
+ self.record.send(self.attribute).klass
81
+ end
82
+
83
+ def search(type:, q:)
84
+
85
+ query_search = search_query_build(klass: remote_alchemy_relation, type: type, q: q, mime_attribute: :image_file_format)
86
+
87
+ self.record.send(self.attribute).joins(:alchemy_file_instance).merge(query_search).uniq.collect do |p|
88
+ path_info(root_path.build_file_path(p))
89
+ end
90
+
91
+ end
92
+
93
+
94
+ def duplicate(t)
95
+ new_path = Rails.root.join('tmp', "copy_#{File.basename(t.name)}")
96
+
97
+ ::FileUtils.cp(t.file.path, new_path)
98
+
99
+ img = ::Alchemy::Picture.new(
100
+ image_file: new_path
101
+ )
102
+ img.name = img.humanized_name
103
+ img.save
104
+
105
+ new_rec = associate_record_to_active_instance(img)
106
+ root_path.build_file_path(new_rec)
107
+ end
108
+
109
+
110
+ def duplicable?(target)
111
+ remote_alchemy_relation == ::Alchemy::Picture
112
+ end
113
+
114
+ ##
115
+ # Nel caso del componente, rm vuol dire dissociare il target elementi
116
+ def rm(target)
117
+ target.active_record_instance.destroy
118
+ end
119
+
120
+ private
121
+
122
+ def associate_record_to_active_instance(rec)
123
+ self.record.class.transaction do
124
+ rec.update_attributes(tag_list: (self.tags + rec.tag_list).flatten.compact)
125
+ self.record.send(self.attribute).create(:alchemy_file_instance => rec)
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,40 @@
1
+ module Alchemy
2
+ module Custom
3
+ module Model
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace Alchemy::Custom::Model
6
+ #engine_name 'alchemy'
7
+
8
+ config.autoload_paths << config.root.join('lib')
9
+
10
+ initializer "alchemy_custom_model.assets.precompile" do |app|
11
+ app.config.assets.precompile << 'alchemy_custom_model_manifest.js'
12
+ app.config.assets.precompile << 'elfinder/css/elfinder.min.css'
13
+ app.config.assets.precompile << 'elfinder/css/theme.css'
14
+ app.config.assets.paths << config.root.join("vendor")
15
+
16
+ end
17
+
18
+ config.to_prepare do
19
+
20
+ Alchemy::PagesController.include(PagesControllerDec)
21
+
22
+ # load degli helpers per alchemy
23
+ [
24
+ Alchemy::Custom::Model::Engine.root.join('app', 'helpers', 'alchemy', 'pages_helper_decorator.rb')
25
+ ].each do |f|
26
+ Rails.configuration.cache_classes ? require(f) : load(f)
27
+ end
28
+
29
+
30
+ end
31
+
32
+
33
+ # initializer "alchemy_richmedia_essences.register_ability" do
34
+ # Alchemy.register_ability Alchemy::Richmedia::Essences::Ability
35
+ # end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,35 @@
1
+ require 'active_support/concern'
2
+
3
+ module Alchemy
4
+ module Custom
5
+ module Model
6
+ module GlobalIdSetter
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+
11
+ private
12
+
13
+ ##
14
+ # Metodo per ricevere un global id ed associare il relativo modello
15
+ #
16
+ def global_id_setter(field)
17
+
18
+ alias_method "_old_#{field}=".to_sym, "#{field}=".to_sym
19
+
20
+ define_method "#{field}=" do |v|
21
+ if v.is_a?(String)
22
+ v = GlobalID::Locator.locate_signed v
23
+ end
24
+ send("_old_#{field}=", v)
25
+ end
26
+
27
+
28
+ end
29
+
30
+
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end