ab_admin 0.8.3 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +11 -5
- data/app/assets/javascripts/ab_admin/components/admin_assets.js.coffee +0 -25
- data/app/assets/javascripts/ab_admin/components/google_translate.js.coffee +3 -5
- data/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +33 -25
- data/app/assets/javascripts/ab_admin/core/batch_actions.js.coffee +1 -1
- data/app/assets/javascripts/ab_admin/core/columns_hider.js.coffee +24 -23
- data/app/assets/javascripts/ab_admin/core/init.js.coffee +7 -2
- data/app/assets/javascripts/ab_admin/core/search_form.js.coffee +1 -7
- data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +23 -7
- data/app/assets/javascripts/ab_admin/core/utils.js.coffee +16 -2
- data/app/assets/javascripts/ab_admin/inputs/datetime_input.js.coffee +1 -0
- data/app/assets/javascripts/ab_admin/main.js +3 -4
- data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.scss +71 -25
- data/app/assets/stylesheets/ab_admin/components/_base.scss +21 -1
- data/app/assets/stylesheets/ab_admin/components/_colored_tabs.scss +1 -1
- data/app/assets/stylesheets/ab_admin/components/_form.scss +16 -18
- data/app/assets/stylesheets/ab_admin/components/_grid_view.scss +2 -2
- data/app/assets/stylesheets/ab_admin/components/_locale_tabs.scss +11 -23
- data/app/assets/stylesheets/ab_admin/components/_navigation.scss +7 -11
- data/app/assets/stylesheets/ab_admin/components/_table_view.scss +85 -11
- data/app/assets/stylesheets/ab_admin/components/_tooltip.scss +81 -0
- data/app/assets/stylesheets/ab_admin/components/_tree_view.scss +1 -1
- data/app/assets/stylesheets/ab_admin/devise.scss +2 -2
- data/app/assets/stylesheets/ab_admin/fileupload.scss +2 -9
- data/app/assets/stylesheets/ab_admin/main.scss +1 -2
- data/app/controllers/admin/assets_controller.rb +1 -1
- data/app/controllers/admin/base_controller.rb +133 -149
- data/app/controllers/admin/dashboards_controller.rb +2 -2
- data/app/controllers/admin/locators_controller.rb +8 -6
- data/app/controllers/admin/manager_controller.rb +19 -49
- data/app/controllers/admin/static_pages_controller.rb +0 -4
- data/app/controllers/admin/structures_controller.rb +2 -2
- data/app/views/ab_admin/devise/sessions/new.html.slim +2 -0
- data/app/views/admin/assets/batch_edit.html.slim +3 -2
- data/app/views/admin/base/_search_layout.html.slim +7 -6
- data/app/views/admin/base/create.js.erb +6 -3
- data/app/views/admin/base/edit.js.erb +1 -1
- data/app/views/admin/base/index.html.slim +4 -4
- data/app/views/admin/base/new.js.erb +1 -1
- data/app/views/admin/base/update.js.erb +7 -2
- data/app/views/admin/fileupload/_asset_templates.html.slim +1 -2
- data/app/views/admin/fileupload/_image.html.slim +1 -2
- data/app/views/admin/locators/edit.html.slim +7 -6
- data/app/views/admin/manager/_map.html.slim +4 -0
- data/app/views/admin/manager/_show_table.html.slim +1 -1
- data/app/views/admin/manager/_stats.html.slim +4 -0
- data/app/views/admin/manager/_table.html.slim +7 -4
- data/app/views/admin/shared/_content_actions.html.slim +35 -30
- data/app/views/admin/shared/_flash.html.slim +5 -4
- data/app/views/admin/shared/_locale_tabs.html.slim +2 -2
- data/app/views/admin/shared/_main_menu.html.slim +1 -1
- data/app/views/admin/shared/_save_buttons.html.slim +10 -1
- data/app/views/admin/structures/_form.html.slim +1 -1
- data/app/views/admin/users/_form.html.slim +3 -3
- data/app/views/admin/users/_search_form.html.slim +1 -1
- data/app/views/layouts/admin/_footer.html.slim +0 -1
- data/app/views/layouts/admin/_navigation.html.slim +1 -1
- data/app/views/layouts/admin/application.html.slim +2 -2
- data/config/locales/de.yml +1 -2
- data/config/locales/en.yml +9 -15
- data/config/locales/it.yml +1 -0
- data/config/locales/ru.yml +0 -1
- data/config/locales/uk.yml +0 -1
- data/db/migrate/20130101000001_create_users.rb +1 -4
- data/db/migrate/20130101000003_create_assets.rb +1 -1
- data/db/migrate/20130101000004_create_headers.rb +5 -5
- data/db/migrate/20130101000005_create_static_pages.rb +2 -5
- data/db/migrate/20130101000006_create_structures.rb +1 -1
- data/db/migrate/20130101000007_base_translations.rb +43 -12
- data/db/migrate/20130101000008_create_admin_comments.rb +2 -7
- data/db/migrate/20130101000009_create_tracks.rb +4 -8
- data/lib/ab_admin/abstract_resource.rb +6 -5
- data/lib/ab_admin/carrierwave/base_uploader.rb +87 -75
- data/lib/ab_admin/carrierwave/glue.rb +0 -5
- data/lib/ab_admin/concerns/admin_addition.rb +15 -27
- data/lib/ab_admin/concerns/translations_macro.rb +97 -0
- data/lib/ab_admin/concerns/utilities.rb +2 -2
- data/lib/ab_admin/config/base.rb +27 -4
- data/lib/ab_admin/controllers/callbacks.rb +3 -26
- data/lib/ab_admin/core_ext/array.rb +1 -50
- data/lib/ab_admin/core_ext/hash.rb +2 -31
- data/lib/ab_admin/core_ext/other.rb +0 -6
- data/lib/ab_admin/core_ext/string.rb +1 -86
- data/lib/ab_admin/devise.rb +7 -0
- data/lib/ab_admin/engine.rb +2 -1
- data/lib/ab_admin/hooks/ckeditor_lazy.rb +13 -0
- data/lib/ab_admin/hooks/will_paginate_id_prefetch.rb +8 -6
- data/lib/ab_admin/hooks/will_paginate_no_uri.rb +1 -1
- data/lib/ab_admin/i18n_tools/google_translate.rb +3 -1
- data/lib/ab_admin/i18n_tools/model_translator.rb +1 -1
- data/lib/ab_admin/menu/base_group.rb +0 -1
- data/lib/ab_admin/menu/group.rb +2 -4
- data/lib/ab_admin/menu/item.rb +4 -8
- data/lib/ab_admin/models/asset.rb +7 -10
- data/lib/ab_admin/models/header.rb +2 -2
- data/lib/ab_admin/models/locator.rb +29 -3
- data/lib/ab_admin/models/settings.rb +2 -2
- data/lib/ab_admin/models/structure.rb +3 -3
- data/lib/ab_admin/models/track.rb +15 -3
- data/lib/ab_admin/models/user.rb +12 -48
- data/lib/ab_admin/utils/csv_document.rb +8 -6
- data/lib/ab_admin/utils/eval_helpers.rb +0 -13
- data/lib/ab_admin/utils/logger.rb +12 -2
- data/lib/ab_admin/utils/mysql.rb +2 -3
- data/lib/ab_admin/utils/xls_document.rb +18 -18
- data/lib/ab_admin/utils.rb +0 -5
- data/lib/ab_admin/version.rb +1 -1
- data/lib/ab_admin/views/admin_helpers.rb +43 -28
- data/lib/ab_admin/views/admin_navigation_helpers.rb +18 -16
- data/lib/ab_admin/views/form_builder.rb +7 -5
- data/lib/ab_admin/views/helpers.rb +0 -9
- data/lib/ab_admin/views/inputs/ckeditor_input.rb +1 -5
- data/lib/ab_admin/views/manager_helpers.rb +15 -6
- data/lib/ab_admin/views/search_form_builder.rb +13 -13
- data/lib/ab_admin/views/will_paginate_bootstrap_renderer.rb +60 -0
- data/lib/ab_admin.rb +44 -32
- data/lib/generators/ab_admin/glob/glob_generator.rb +4 -5
- data/lib/generators/ab_admin/glob/templates/migration.erb +10 -7
- data/lib/generators/ab_admin/install/templates/config/ab_admin.rb.erb +1 -1
- data/lib/generators/ab_admin/install/templates/models/user.rb +1 -13
- data/lib/generators/ab_admin/install/templates/spec/spec_helper.rb +0 -1
- data/lib/generators/ab_admin/install/templates/spec/support/database_cleaner.rb +8 -11
- data/lib/generators/ab_admin/install/templates/uploaders/attachment_file_uploader.rb +1 -1
- data/lib/generators/ab_admin/install/templates/uploaders/avatar_uploader.rb +1 -1
- data/lib/generators/ab_admin/install/templates/uploaders/picture_uploader.rb +16 -3
- data/lib/generators/ab_admin/model/model_generator.rb +3 -4
- data/lib/generators/ab_admin/model/templates/resource.erb +5 -2
- data/lib/generators/ab_admin/resource/resource_generator.rb +0 -4
- data/lib/generators/ab_admin/resource/templates/controller.erb +2 -9
- data/lib/tasks/assets.rake +5 -5
- metadata +45 -85
- data/app/assets/images/admin/Jcrop.gif +0 -0
- data/app/assets/images/admin/flags/de.png +0 -0
- data/app/assets/images/admin/flags/en.png +0 -0
- data/app/assets/images/admin/flags/es.png +0 -0
- data/app/assets/images/admin/flags/fr.png +0 -0
- data/app/assets/images/admin/flags/it.png +0 -0
- data/app/assets/images/admin/flags/ja.png +0 -0
- data/app/assets/images/admin/flags/pl.png +0 -0
- data/app/assets/images/admin/flags/ru.png +0 -0
- data/app/assets/images/admin/flags/uk.png +0 -0
- data/app/assets/javascripts/ab_admin/components/croppable_image.js.coffee +0 -33
- data/app/assets/stylesheets/ab_admin/components/_columns_hider.scss +0 -5
- data/app/assets/stylesheets/ab_admin/components/_perms.scss +0 -39
- data/app/views/admin/shared/_columns_hider.html.slim +0 -9
- data/lib/ab_admin/hooks/globalize_locale_suffix_accessors.rb +0 -25
- data/lib/ab_admin/hooks/globalize_valid_locale.rb +0 -9
- data/lib/generators/ab_admin/ckeditor_assets/ckeditor_assets_generator.rb +0 -19
- data/lib/generators/template.rb +0 -96
@@ -1,15 +1,46 @@
|
|
1
|
-
class BaseTranslations < ActiveRecord::Migration
|
2
|
-
def
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
1
|
+
class BaseTranslations < ActiveRecord::Migration[5.2]
|
2
|
+
def change
|
3
|
+
create_table :static_page_translations do |t|
|
4
|
+
t.references :static_page, null: false
|
5
|
+
t.string :locale, limit: 5, null: false
|
6
|
+
t.string :title
|
7
|
+
t.text :content
|
8
|
+
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
add_index :static_page_translations, [:static_page_id, :locale], unique: true, name: 'static_pages_ts_static_page_id_locale'
|
12
|
+
|
13
|
+
create_table :header_translations do |t|
|
14
|
+
t.references :header, null: false
|
15
|
+
t.string :locale, limit: 5, null: false
|
16
|
+
t.string :title
|
17
|
+
t.string :h1
|
18
|
+
t.string :keywords
|
19
|
+
t.text :description
|
20
|
+
t.text :seo_block
|
21
|
+
|
22
|
+
t.timestamps
|
23
|
+
end
|
24
|
+
add_index :header_translations, [:header_id, :locale], unique: true, name: 'headers_ts_header_id_locale'
|
25
|
+
|
26
|
+
create_table :structure_translations do |t|
|
27
|
+
t.references :structure, null: false
|
28
|
+
t.string :locale, limit: 5, null: false
|
29
|
+
t.string :title
|
30
|
+
t.string :redirect_url
|
31
|
+
|
32
|
+
t.timestamps
|
33
|
+
end
|
34
|
+
add_index :structure_translations, [:structure_id, :locale], unique: true, name: 'structures_ts_structure_id_locale'
|
35
|
+
|
36
|
+
create_table :asset_translations do |t|
|
37
|
+
t.references :asset, null: false
|
38
|
+
t.string :locale, limit: 5, null: false
|
39
|
+
t.string :name
|
40
|
+
t.string :alt
|
8
41
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
Structure.drop_translation_table!
|
13
|
-
Asset.drop_translation_table!
|
42
|
+
t.timestamps
|
43
|
+
end
|
44
|
+
add_index :asset_translations, [:asset_id, :locale], unique: true, name: 'assets_ts_asset_id_locale'
|
14
45
|
end
|
15
46
|
end
|
@@ -1,18 +1,13 @@
|
|
1
|
-
class CreateAdminComments < ActiveRecord::Migration
|
1
|
+
class CreateAdminComments < ActiveRecord::Migration[5.2]
|
2
2
|
def change
|
3
3
|
create_table :admin_comments do |t|
|
4
4
|
t.references :user
|
5
5
|
t.string :user_name
|
6
|
-
t.
|
7
|
-
t.string :resource_type, limit: 50, null: false
|
6
|
+
t.references :resource, polymorphic: true
|
8
7
|
t.references :resource_user
|
9
8
|
t.text :body
|
10
9
|
|
11
10
|
t.timestamps
|
12
11
|
end
|
13
|
-
|
14
|
-
add_index :admin_comments, :user_id
|
15
|
-
add_index :admin_comments, :resource_user_id
|
16
|
-
add_index :admin_comments, [:resource_type, :resource_id]
|
17
12
|
end
|
18
13
|
end
|
@@ -1,20 +1,16 @@
|
|
1
|
-
class CreateTracks < ActiveRecord::Migration
|
1
|
+
class CreateTracks < ActiveRecord::Migration[5.2]
|
2
2
|
def change
|
3
3
|
create_table :tracks do |t|
|
4
4
|
t.string :name
|
5
5
|
t.string :key
|
6
|
-
t.
|
7
|
-
t.
|
8
|
-
t.
|
6
|
+
t.references :trackable, polymorphic: true
|
7
|
+
t.references :user
|
8
|
+
t.references :owner
|
9
9
|
t.column :trackable_changes, :mediumtext
|
10
10
|
t.text :parameters
|
11
11
|
|
12
12
|
t.timestamps
|
13
13
|
end
|
14
|
-
|
15
|
-
add_index :tracks, [:trackable_type, :trackable_id]
|
16
|
-
add_index :tracks, :owner_id
|
17
|
-
add_index :tracks, :user_id
|
18
14
|
add_index :tracks, :key
|
19
15
|
end
|
20
16
|
end
|
@@ -6,14 +6,15 @@ module AbAdmin
|
|
6
6
|
ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy, :preview, :batch, :rebuild, :custom_action, :history]
|
7
7
|
end
|
8
8
|
|
9
|
-
attr_accessor :model, :table, :search, :export, :form, :chart, :
|
10
|
-
:
|
9
|
+
attr_accessor :model, :table, :search, :export, :form, :chart, :stats, :map, :modal_form, :show,
|
10
|
+
:preview_path, :actions, :custom_settings,
|
11
|
+
:batch_actions, :action_items, :disabled_action_items, :resource_action_items, :tree_node_renderer,
|
11
12
|
:parent_resources, :custom_actions, :permitted_params, :scopes
|
12
13
|
|
13
14
|
def initialize
|
14
15
|
@actions = ACTIONS
|
15
16
|
@custom_settings = {}
|
16
|
-
@
|
17
|
+
@batch_actions= [AbAdmin::Config::BatchAction.new(:destroy, confirm: I18n.t('admin.delete_confirmation'))]
|
17
18
|
@action_items = []
|
18
19
|
@disabled_action_items = []
|
19
20
|
@default_action_items_for = {}
|
@@ -87,9 +88,9 @@ module AbAdmin
|
|
87
88
|
|
88
89
|
def batch_action(name, options={}, &block)
|
89
90
|
if options
|
90
|
-
instance.
|
91
|
+
instance.batch_actions << AbAdmin::Config::BatchAction.new(name.to_sym, options, &block)
|
91
92
|
else
|
92
|
-
instance.
|
93
|
+
instance.batch_actions.reject!{|a| a.name == name.to_sym }
|
93
94
|
end
|
94
95
|
end
|
95
96
|
|
@@ -1,4 +1,3 @@
|
|
1
|
-
require 'mime/types'
|
2
1
|
require 'mini_magick'
|
3
2
|
require 'carrierwave/processing/mini_magick'
|
4
3
|
|
@@ -8,8 +7,7 @@ module AbAdmin
|
|
8
7
|
include ::CarrierWave::MiniMagick
|
9
8
|
include AbAdmin::Utils::EvalHelpers
|
10
9
|
|
11
|
-
class_attribute :
|
12
|
-
self.transliterate = true
|
10
|
+
class_attribute :human_filenames
|
13
11
|
self.human_filenames = true
|
14
12
|
|
15
13
|
attr_accessor :internal_identifier
|
@@ -26,41 +24,48 @@ module AbAdmin
|
|
26
24
|
|
27
25
|
process :set_model_info
|
28
26
|
|
29
|
-
def
|
30
|
-
"#{
|
27
|
+
def filename
|
28
|
+
"#{[human_part, secure_token].compact.join('_')}#{extension}"
|
31
29
|
end
|
32
30
|
|
33
|
-
def
|
34
|
-
|
31
|
+
def full_filename(*)
|
32
|
+
return filename unless version_name
|
33
|
+
base = "#{version_filename_part}#{version_extension}"
|
34
|
+
return base unless human_filenames
|
35
|
+
[human_part, base].compact.join('_')
|
35
36
|
end
|
36
37
|
|
37
|
-
def
|
38
|
-
|
39
|
-
return secure_token unless version_name
|
40
|
-
version_name.to_s.start_with?('retina_') ? "#{version_name.to_s.sub(/^retina_/, '')}@2x" : version_name.to_s
|
38
|
+
def human_part
|
39
|
+
normalize_filename(model.send("#{mounted_as}_file_name").to_s.strip.remove(/\.\w+$/)).remove(secure_token).chomp('_').presence
|
41
40
|
end
|
42
41
|
|
43
|
-
def
|
44
|
-
|
42
|
+
def extension
|
43
|
+
File.extname(model.original_name).downcase
|
45
44
|
end
|
46
45
|
|
47
|
-
def
|
48
|
-
|
49
|
-
system_part = base_filename_part
|
50
|
-
human_filename_part = for_file.chomp(ext)
|
51
|
-
return "#{system_part || version_name}#{ext}" if human_filename_part == secure_token
|
52
|
-
system_part ? "#{human_filename_part}_#{system_part}#{ext}" : "#{human_filename_part}#{ext}"
|
46
|
+
def version_extension
|
47
|
+
webp? ? '.webp' : extension
|
53
48
|
end
|
54
49
|
|
55
|
-
def
|
56
|
-
|
50
|
+
def version_filename_part
|
51
|
+
return secure_token unless version_name
|
52
|
+
strict_version_name = version_name.to_s.remove('retina_').remove('_webp')
|
53
|
+
strict_version_name = nil if strict_version_name.to_sym == :default
|
54
|
+
"#{strict_version_name}#{'@2x' if retina?}"
|
57
55
|
end
|
58
56
|
|
59
|
-
# use secure token in the filename for non processed image
|
60
57
|
def secure_token
|
61
58
|
model.data_secure_token ||= AbAdmin.friendly_token(20).downcase
|
62
59
|
end
|
63
60
|
|
61
|
+
def retina?
|
62
|
+
version_name.to_s.start_with?('retina_')
|
63
|
+
end
|
64
|
+
|
65
|
+
def webp?
|
66
|
+
version_name.to_s.end_with?('_webp')
|
67
|
+
end
|
68
|
+
|
64
69
|
def store_model_filename(record)
|
65
70
|
old_file_name = filename
|
66
71
|
new_file_name = model_filename(old_file_name, record)
|
@@ -68,69 +73,81 @@ module AbAdmin
|
|
68
73
|
rename_via_move(new_file_name)
|
69
74
|
end
|
70
75
|
|
71
|
-
|
72
|
-
|
73
|
-
def filename
|
74
|
-
internal_identifier || model.send("#{mounted_as}_file_name") || (store_filename && "#{secure_token}#{File.extname(store_filename).downcase}")
|
75
|
-
end
|
76
|
-
|
77
|
-
def write_internal_identifier(internal_identifier)
|
78
|
-
self.internal_identifier = internal_identifier
|
79
|
-
versions.values.each{|v| v.internal_identifier = internal_identifier }
|
76
|
+
def save_original_name(file)
|
77
|
+
model.original_name ||= file.original_filename if file.respond_to?(:original_filename)
|
80
78
|
end
|
81
79
|
|
82
|
-
# transliterate original filename
|
83
|
-
# allow to build custom filename
|
84
80
|
def model_filename(base_filename, record)
|
85
81
|
custom_file_name = model.build_filename(base_filename, record)
|
86
82
|
return unless custom_file_name
|
87
|
-
normalize_filename(custom_file_name)
|
83
|
+
normalize_filename(custom_file_name)
|
88
84
|
end
|
85
|
+
private :model_filename
|
89
86
|
|
90
87
|
def normalize_filename(raw_filename)
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
to_path = File.join(dir, v.full_filename(new_file_name))
|
104
|
-
next if from_path == to_path || !File.exists?(from_path)
|
105
|
-
moves << [from_path, to_path]
|
106
|
-
end
|
107
|
-
moves.each { |move| FileUtils.mv(*move) }
|
88
|
+
I18n.transliterate(raw_filename.unicode_normalize).parameterize(separator: '_').gsub(/[\-_]+/, '_').downcase
|
89
|
+
end
|
90
|
+
|
91
|
+
def rename_via_move(new_filename)
|
92
|
+
dir = File.dirname(path)
|
93
|
+
old_names = versions.values.unshift(self).map(&:full_filename)
|
94
|
+
model.send("#{mounted_as}_file_name=", "#{[new_filename.presence, secure_token].compact.join('_')}#{extension}")
|
95
|
+
new_names = versions.values.unshift(self).map(&:full_filename)
|
96
|
+
old_names.zip(new_names).each do |old_name, new_name|
|
97
|
+
old_path, new_path = File.join(dir, old_name), File.join(dir, new_name)
|
98
|
+
next if old_path == new_path || !File.exist?(old_path)
|
99
|
+
FileUtils.mv(old_path, new_path)
|
108
100
|
end
|
109
|
-
|
110
|
-
write_internal_identifier new_file_name
|
111
|
-
model.send("write_#{mounted_as}_identifier")
|
112
|
-
retrieve_from_store!(new_file_name) if human_filenames
|
113
|
-
|
114
|
-
new_file_name
|
101
|
+
retrieve_from_store!(model.send("#{mounted_as}_file_name"))
|
115
102
|
end
|
116
103
|
|
117
|
-
private :write_internal_identifier, :store_filename, :model_filename
|
118
|
-
|
119
|
-
def rmagick_included?
|
120
|
-
self.class.included_modules.map(&:to_s).include?('CarrierWave::RMagick')
|
121
|
-
end
|
122
|
-
|
123
|
-
# prevent large number of subdirectories
|
124
104
|
def store_dir
|
125
105
|
str_id = model.id.to_s.rjust(4, '0')
|
126
106
|
[AbAdmin.uploads_dir, model.class.to_s.underscore, str_id[0..2], str_id[3..-1]].join('/')
|
127
107
|
end
|
128
108
|
|
109
|
+
def convert_to_webp(options = {})
|
110
|
+
webp_path = "#{File.dirname(path)}/#{full_filename}"
|
111
|
+
WebP.encode(path, webp_path, options_for_webp(options))
|
112
|
+
@file = ::CarrierWave::SanitizedFile.new(tempfile: webp_path, filename: webp_path, content_type: 'image/webp')
|
113
|
+
end
|
114
|
+
|
115
|
+
def options_for_webp(options)
|
116
|
+
w, h = width, height
|
117
|
+
options = options.dup
|
118
|
+
ratio = w.to_f / h
|
119
|
+
if options[:resize_to_fill]
|
120
|
+
res_w, res_h = options[:resize_to_fill]
|
121
|
+
res_ratio = res_w.to_f / res_h
|
122
|
+
options.update(resize_w: res_w, resize_h: res_h) unless w == res_w && h == res_h
|
123
|
+
if ratio > res_ratio
|
124
|
+
crop_res_w = h * res_ratio
|
125
|
+
crop_res_h = h
|
126
|
+
options.update(crop_x: ((w - crop_res_w) / 2).to_i, crop_y: 0, crop_w: crop_res_w.to_i, crop_h: crop_res_h.to_i)
|
127
|
+
elsif ratio < res_ratio
|
128
|
+
crop_res_w = w
|
129
|
+
crop_res_h = w / res_ratio
|
130
|
+
options.update(crop_x: 0, crop_y: ((h - crop_res_h) / 2).to_i, crop_w: crop_res_w.to_i, crop_h: crop_res_h.to_i)
|
131
|
+
end
|
132
|
+
elsif options[:resize_to_fit]
|
133
|
+
res_w, res_h = options[:resize_to_fit]
|
134
|
+
res_ratio = res_w.to_f / res_h
|
135
|
+
if ratio == res_ratio
|
136
|
+
options.update(resize_w: res_w, resize_h: res_h) unless w == res_w && h == res_h
|
137
|
+
elsif ratio > res_ratio
|
138
|
+
options.update(resize_w: res_h)
|
139
|
+
elsif ratio < res_ratio
|
140
|
+
options.update(resize_h: res_w)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
options.except(:resize_to_fill, :resize_to_fit)
|
144
|
+
end
|
145
|
+
|
129
146
|
# Strips out all embedded information from the image
|
130
147
|
# process :strip
|
131
148
|
#
|
132
149
|
def strip
|
133
|
-
|
150
|
+
minimagick! do |img|
|
134
151
|
img.strip
|
135
152
|
img = yield(img) if block_given?
|
136
153
|
img
|
@@ -144,7 +161,7 @@ module AbAdmin
|
|
144
161
|
percentage = normalize_param(percentage)
|
145
162
|
|
146
163
|
unless percentage.blank?
|
147
|
-
|
164
|
+
minimagick! do |img|
|
148
165
|
img.quality percentage.to_s
|
149
166
|
img = yield(img) if block_given?
|
150
167
|
img
|
@@ -160,7 +177,7 @@ module AbAdmin
|
|
160
177
|
|
161
178
|
unless degrees.blank?
|
162
179
|
manipulate! do |img|
|
163
|
-
|
180
|
+
self.class.included_modules.map(&:to_s).include?('CarrierWave::RMagick') ? img.rotate!(degrees.to_i) : img.rotate(degrees.to_s)
|
164
181
|
img = yield(img) if block_given?
|
165
182
|
img
|
166
183
|
end
|
@@ -176,7 +193,7 @@ module AbAdmin
|
|
176
193
|
geometry = normalize_param(geometry[0]) if geometry.size == 1
|
177
194
|
|
178
195
|
if geometry && geometry.size == 4
|
179
|
-
|
196
|
+
minimagick! do |img|
|
180
197
|
img.crop '%ix%i+%i+%i' % geometry
|
181
198
|
img = yield(img) if block_given?
|
182
199
|
img
|
@@ -185,7 +202,7 @@ module AbAdmin
|
|
185
202
|
end
|
186
203
|
|
187
204
|
def watermark(watermark_path, gravity='SouthEast')
|
188
|
-
|
205
|
+
minimagick! do |img|
|
189
206
|
resolved_path = watermark_path.is_a?(Symbol) ? send(watermark_path) : watermark_path
|
190
207
|
watermark_image = ::MiniMagick::Image.open(resolved_path)
|
191
208
|
img.composite(watermark_image) { |c| c.gravity gravity }
|
@@ -202,12 +219,7 @@ module AbAdmin
|
|
202
219
|
end
|
203
220
|
|
204
221
|
def dimensions
|
205
|
-
[
|
206
|
-
end
|
207
|
-
|
208
|
-
def magick
|
209
|
-
#@magick ||= ::MiniMagick::Image.new(current_path)
|
210
|
-
::MiniMagick::Image.new(current_path)
|
222
|
+
[width, height]
|
211
223
|
end
|
212
224
|
|
213
225
|
protected
|
@@ -11,11 +11,6 @@ module AbAdmin
|
|
11
11
|
mount_uploader(:data, uploader, options, &block)
|
12
12
|
end
|
13
13
|
|
14
|
-
def sunrise_uploader(*args)
|
15
|
-
ActiveSupport::Deprecation.warn('`sunrise_uploader` is deprecated, use `ab_admin_uploader` instead')
|
16
|
-
ab_admin_uploader(*args)
|
17
|
-
end
|
18
|
-
|
19
14
|
def validates_filesize_of(*attr_names)
|
20
15
|
validates_with FileSizeValidator, _merge_attributes(attr_names)
|
21
16
|
end
|
@@ -4,19 +4,23 @@ module AbAdmin
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
+
attr_accessor :last_updated_timestamp
|
8
|
+
validate :do_not_overwrite, if: :last_updated_timestamp
|
7
9
|
scope(:admin, proc { all }) unless respond_to?(:admin)
|
8
10
|
scope(:base, -> { all }) unless respond_to?(:base)
|
9
|
-
scope :by_ids, lambda { |ids| where("#{quoted_table_name}.id IN (?)", AbAdmin.val_to_array(ids).push(0)) } unless respond_to?(:by_ids)
|
10
11
|
|
11
12
|
class_attribute :batch_actions, instance_writer: false
|
12
13
|
self.batch_actions = [:destroy]
|
13
14
|
end
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
def updated_timestamp(associations: true)
|
17
|
+
res = [updated_at]
|
18
|
+
res += translations.map(&:updated_at) if self.class.translates?
|
19
|
+
if associations
|
20
|
+
associations = self.class.nested_attributes_options.keys unless associations.is_a?(Array)
|
21
|
+
res += associations.flat_map{|assoc| Array(send(assoc)).map(&:updated_timestamp) }
|
19
22
|
end
|
23
|
+
res.compact.max
|
20
24
|
end
|
21
25
|
|
22
26
|
def for_input_token
|
@@ -27,28 +31,6 @@ module AbAdmin
|
|
27
31
|
"#{self.class.model_name.human(count: 1)} ##{self.id} #{AbAdmin.safe_display_name(self)}"
|
28
32
|
end
|
29
33
|
|
30
|
-
def translated_any(attr)
|
31
|
-
send(attr).presence || translations.detect { |r| r.send(attr).present? }.try!(attr)
|
32
|
-
end
|
33
|
-
|
34
|
-
def new_changes
|
35
|
-
excluded_attrs = [:updated_at]
|
36
|
-
excluded_attrs += translated_attribute_names if self.class.translates?
|
37
|
-
all_changes = changes.except(*excluded_attrs).map { |k, v| [k, v[1]] }.to_h
|
38
|
-
if self.class.translates?
|
39
|
-
globalize.dirty.each do |attr, changes|
|
40
|
-
changes.each do |change|
|
41
|
-
all_changes["#{attr}_#{change[0]}"] = send("#{attr}_#{change[0]}")
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
all_changes
|
46
|
-
end
|
47
|
-
|
48
|
-
def admin_comments_count_non_zero
|
49
|
-
self[:admin_comments_count].to_i.zero? ? nil : self[:admin_comments_count]
|
50
|
-
end
|
51
|
-
|
52
34
|
def token_data(method, options={})
|
53
35
|
assoc = self.class.reflect_on_association(method)
|
54
36
|
scope = send(method)
|
@@ -93,6 +75,12 @@ module AbAdmin
|
|
93
75
|
scope.where(sql, val: send(order_col)).ransack(query[:q]).result(distinct: true).first
|
94
76
|
end
|
95
77
|
|
78
|
+
private
|
79
|
+
|
80
|
+
def do_not_overwrite
|
81
|
+
return if new_record? || last_updated_timestamp.blank?
|
82
|
+
errors.add(:base, :changed) if updated_timestamp.to_i > last_updated_timestamp.to_i
|
83
|
+
end
|
96
84
|
end
|
97
85
|
end
|
98
86
|
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module AbAdmin
|
2
|
+
module Concerns
|
3
|
+
module TranslationsMacro
|
4
|
+
def translates(*attr_names)
|
5
|
+
options = attr_names.extract_options!
|
6
|
+
setup_translations(options) unless translates?
|
7
|
+
add_translated_attributes(attr_names.map(&:to_sym) - translated_attribute_names)
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup_translations(options)
|
11
|
+
include InstanceMethods
|
12
|
+
extend ClassMethods
|
13
|
+
|
14
|
+
class_attribute :translated_attribute_names, :translation_options
|
15
|
+
self.translated_attribute_names = []
|
16
|
+
self.translation_options = options
|
17
|
+
|
18
|
+
has_many :translations, class_name: translation_class.name, foreign_key: class_name.foreign_key, dependent: :destroy, autosave: true, inverse_of: :translated_model
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_translated_attributes(attr_names)
|
22
|
+
attr_names.each do |attr_name|
|
23
|
+
define_translation_accessors(attr_name)
|
24
|
+
self.translated_attribute_names << attr_name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def define_translation_accessors(attr_name)
|
29
|
+
define_method("#{attr_name}_translation") { translation_for_locale(I18n.locale).try!(:send, attr_name) }
|
30
|
+
define_method("#{attr_name}_translation=") {|v| translation_for_locale(I18n.locale).try!(:send, "#{attr_name}=", v) }
|
31
|
+
alias_method attr_name, "#{attr_name}_translation"
|
32
|
+
alias_method "#{attr_name}=", "#{attr_name}_translation="
|
33
|
+
define_method("#{attr_name}_default"){ translation_for_locale(I18n.default_locale).try!(:send, attr_name) }
|
34
|
+
AbAdmin.translated_locales.each do |l|
|
35
|
+
define_method("#{attr_name}_#{l}") {translation_for_locale(l).try!(:send, attr_name)}
|
36
|
+
define_method("#{attr_name}_#{l}=") {|v| translation_for_locale(l).try!(:send, "#{attr_name}=", v)}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def class_name
|
41
|
+
name.split('::').last
|
42
|
+
end
|
43
|
+
|
44
|
+
def translates?
|
45
|
+
included_modules.include?(InstanceMethods)
|
46
|
+
end
|
47
|
+
|
48
|
+
module InstanceMethods
|
49
|
+
def translation_for_locale(l)
|
50
|
+
return unless AbAdmin.translated_locales.include?(l)
|
51
|
+
translations.detect{|r| r.locale == l.to_s} || translations.new(locale: l.to_s)
|
52
|
+
end
|
53
|
+
|
54
|
+
def translated_attributes
|
55
|
+
translated_attribute_names.map{|attr| [attr, send(attr)] }.to_h.stringify_keys
|
56
|
+
end
|
57
|
+
|
58
|
+
def attributes
|
59
|
+
super.merge!(translated_attributes)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module ClassMethods
|
64
|
+
def translation_class
|
65
|
+
@translation_class ||= begin
|
66
|
+
klass = self.const_defined?(:Translation, false) ? self.const_get(:Translation, false) : self.const_set(:Translation, Class.new(BaseTranslation))
|
67
|
+
klass.belongs_to :translated_model, class_name: self.name, foreign_key: class_name.foreign_key, inverse_of: :translations, touch: translation_options.fetch(:touch, false)
|
68
|
+
klass
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def translations_table_name
|
73
|
+
translation_class.table_name
|
74
|
+
end
|
75
|
+
|
76
|
+
def translated?(name)
|
77
|
+
translated_attribute_names.include?(name.to_sym)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class BaseTranslation < ::ActiveRecord::Base
|
83
|
+
self.abstract_class = true
|
84
|
+
|
85
|
+
validates :locale, presence: true
|
86
|
+
after_initialize :init
|
87
|
+
|
88
|
+
def init
|
89
|
+
self.locale ||= I18n.locale.to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.table_exists?
|
93
|
+
table_name.present? && super
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -70,7 +70,7 @@ module AbAdmin
|
|
70
70
|
add_cond << assoc.klass.instance_exec(&assoc.scope).to_sql[/WHERE(.*?)(?:(?:ORDER|LIMIT).*)?$/, 1] if assoc.scope
|
71
71
|
if assoc.klass.default_scopes.present?
|
72
72
|
assoc.klass.default_scopes.each do |scope|
|
73
|
-
add_cond << scope.call.to_sql[/WHERE(.*?)(?:(?:ORDER|LIMIT).*)?$/, 1]
|
73
|
+
add_cond << scope.scope.call.to_sql[/WHERE(.*?)(?:(?:ORDER|LIMIT).*)?$/, 1]
|
74
74
|
end
|
75
75
|
end
|
76
76
|
count_klass = assoc_count.klass
|
@@ -85,7 +85,7 @@ module AbAdmin
|
|
85
85
|
|
86
86
|
def all_translated_attribute_names
|
87
87
|
if translates?
|
88
|
-
|
88
|
+
AbAdmin.translated_locales.map do |loc|
|
89
89
|
translated_attribute_names.map { |attr| "#{attr}_#{loc}" }
|
90
90
|
end.flatten
|
91
91
|
else
|
data/lib/ab_admin/config/base.rb
CHANGED
@@ -23,12 +23,20 @@ module AbAdmin
|
|
23
23
|
next if column_name == :id || options[:skip].try(:include?, column_name)
|
24
24
|
builder.field(column_name)
|
25
25
|
end
|
26
|
+
model.translated_attribute_names.each do |column_name|
|
27
|
+
builder.field(column_name, sortable: false)
|
28
|
+
end if model.translates?
|
26
29
|
end
|
27
30
|
end
|
28
31
|
end
|
29
32
|
|
30
33
|
class Table < BaseBuilder
|
31
34
|
self.partial_name = 'table'
|
35
|
+
|
36
|
+
def row_html_class
|
37
|
+
return :row_html_class if options[:row_html_class].is_a?(TrueClass)
|
38
|
+
options[:row_html_class]
|
39
|
+
end
|
32
40
|
end
|
33
41
|
|
34
42
|
class Search < BaseBuilder
|
@@ -39,6 +47,14 @@ module AbAdmin
|
|
39
47
|
self.partial_name = 'chart'
|
40
48
|
end
|
41
49
|
|
50
|
+
class Stats < BaseBuilder
|
51
|
+
self.partial_name = 'stats'
|
52
|
+
end
|
53
|
+
|
54
|
+
class Map < BaseBuilder
|
55
|
+
self.partial_name = 'map'
|
56
|
+
end
|
57
|
+
|
42
58
|
class Export < BaseBuilder
|
43
59
|
def render_options
|
44
60
|
{column_names: fields.map(&:name), column_data: fields.map(&:data),
|
@@ -111,7 +127,7 @@ module AbAdmin
|
|
111
127
|
end
|
112
128
|
|
113
129
|
class BatchAction
|
114
|
-
attr_reader :name, :options, :data, :
|
130
|
+
attr_reader :name, :options, :data, :form
|
115
131
|
|
116
132
|
def initialize(name, options={}, &block)
|
117
133
|
@name = name
|
@@ -119,10 +135,13 @@ module AbAdmin
|
|
119
135
|
if options.has_key?(:form)
|
120
136
|
@form = options[:form].is_a?(String) ? options[:form] : "##{name}_batch_form"
|
121
137
|
end
|
122
|
-
@title = options[:title] || I18n.t("admin.actions.batch_#{name}.link", default: name.to_s.humanize)
|
123
138
|
@data = block_given? ? block : name.to_sym
|
124
139
|
end
|
125
140
|
|
141
|
+
def title
|
142
|
+
options[:title] || I18n.t("admin.actions.#{name}.title", default: name.to_s.humanize)
|
143
|
+
end
|
144
|
+
|
126
145
|
def confirm
|
127
146
|
options[:confirm]
|
128
147
|
end
|
@@ -169,8 +188,12 @@ module AbAdmin
|
|
169
188
|
@data = block
|
170
189
|
end
|
171
190
|
|
172
|
-
def
|
173
|
-
|
191
|
+
def param_name
|
192
|
+
options[:as] || name
|
193
|
+
end
|
194
|
+
|
195
|
+
def apply(context, relation)
|
196
|
+
data.is_a?(Proc) ? data.call(context, relation) : relation.public_send(name)
|
174
197
|
end
|
175
198
|
end
|
176
199
|
end
|