ab_admin 0.9.0 → 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/app/assets/javascripts/ab_admin/components/in_place_edit.js.coffee +28 -24
- data/app/assets/javascripts/ab_admin/core/batch_actions.js.coffee +1 -1
- data/app/assets/javascripts/ab_admin/core/init.js.coffee +1 -0
- data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +21 -1
- data/app/assets/javascripts/ab_admin/core/utils.js.coffee +8 -0
- data/app/assets/javascripts/ab_admin/inputs/datetime_input.js.coffee +1 -0
- data/app/assets/javascripts/ab_admin/main.js +1 -2
- data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.scss +44 -23
- data/app/assets/stylesheets/ab_admin/components/_colored_tabs.scss +1 -1
- data/app/assets/stylesheets/ab_admin/components/_form.scss +3 -1
- data/app/assets/stylesheets/ab_admin/components/_navigation.scss +7 -2
- data/app/assets/stylesheets/ab_admin/components/_table_view.scss +75 -9
- data/app/assets/stylesheets/ab_admin/components/_tooltip.scss +1 -0
- data/app/assets/stylesheets/ab_admin/main.scss +1 -1
- data/app/controllers/admin/assets_controller.rb +1 -1
- data/app/controllers/admin/base_controller.rb +87 -107
- data/app/controllers/admin/manager_controller.rb +17 -47
- data/app/views/ab_admin/devise/sessions/new.html.slim +2 -0
- data/app/views/admin/assets/batch_edit.html.slim +2 -1
- data/app/views/admin/base/_search_layout.html.slim +1 -1
- data/app/views/admin/base/create.js.erb +1 -1
- data/app/views/admin/base/edit.js.erb +1 -1
- data/app/views/admin/base/new.js.erb +1 -1
- data/app/views/admin/base/update.js.erb +3 -3
- 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 +6 -3
- data/app/views/admin/shared/_content_actions.html.slim +22 -15
- data/app/views/admin/shared/_save_buttons.html.slim +10 -1
- data/app/views/admin/users/_form.html.slim +2 -2
- data/config/locales/en.yml +8 -13
- data/config/locales/it.yml +1 -0
- 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 -74
- data/lib/ab_admin/carrierwave/glue.rb +0 -5
- data/lib/ab_admin/concerns/admin_addition.rb +19 -1
- data/lib/ab_admin/concerns/utilities.rb +1 -1
- data/lib/ab_admin/config/base.rb +20 -4
- data/lib/ab_admin/core_ext/array.rb +0 -5
- data/lib/ab_admin/core_ext/string.rb +1 -6
- data/lib/ab_admin/devise.rb +7 -0
- data/lib/ab_admin/engine.rb +1 -1
- data/lib/ab_admin/hooks/ckeditor_lazy.rb +13 -0
- 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/locator.rb +1 -1
- 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/utils/csv_document.rb +4 -4
- data/lib/ab_admin/utils/eval_helpers.rb +0 -16
- 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 +1 -3
- data/lib/ab_admin/utils.rb +0 -5
- data/lib/ab_admin/version.rb +1 -1
- data/lib/ab_admin/views/admin_helpers.rb +33 -16
- data/lib/ab_admin/views/admin_navigation_helpers.rb +12 -9
- data/lib/ab_admin/views/inputs/ckeditor_input.rb +1 -5
- data/lib/ab_admin/views/manager_helpers.rb +9 -3
- data/lib/ab_admin/views/search_form_builder.rb +12 -12
- data/lib/ab_admin.rb +13 -2
- data/lib/generators/ab_admin/install/templates/models/user.rb +1 -2
- 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/resource/resource_generator.rb +0 -4
- data/lib/generators/ab_admin/resource/templates/controller.erb +0 -7
- data/lib/tasks/assets.rake +5 -5
- metadata +28 -26
data/config/locales/en.yml
CHANGED
@@ -18,22 +18,13 @@ en:
|
|
18
18
|
actions:
|
19
19
|
activate:
|
20
20
|
link: Activate
|
21
|
-
batch_destroy:
|
22
|
-
confirmation: Are you sure you want to delete the selected records?
|
23
|
-
link: Delete selected
|
24
|
-
title: Multi-remove
|
25
|
-
batch_publish:
|
26
|
-
link: Publish selected
|
27
|
-
title: Multi-publish
|
28
|
-
batch_un_publish:
|
29
|
-
link: Unpublish selected
|
30
|
-
title: Multi-hiding
|
31
21
|
create:
|
32
22
|
link: Create
|
33
23
|
title: Creation
|
34
24
|
destroy:
|
35
|
-
link:
|
36
|
-
title:
|
25
|
+
link: Destroy
|
26
|
+
title: Destroy
|
27
|
+
confirmation: Are you sure you want to delete the selected records?
|
37
28
|
edit:
|
38
29
|
link: Edit
|
39
30
|
title: Editing
|
@@ -94,7 +85,7 @@ en:
|
|
94
85
|
comments:
|
95
86
|
add: Comment
|
96
87
|
title_content: Comments (%{count})
|
97
|
-
delete:
|
88
|
+
delete: Destroy
|
98
89
|
delete_confirmation: Are you sure you want to delete this?
|
99
90
|
empty: Empty
|
100
91
|
exit: Output
|
@@ -109,6 +100,8 @@ en:
|
|
109
100
|
form:
|
110
101
|
cancel: Cancel
|
111
102
|
save: Save
|
103
|
+
force_save: Force save
|
104
|
+
refresh: Refresh
|
112
105
|
save_and_add_another: Save and add new
|
113
106
|
save_and_edit: Save and continue editing
|
114
107
|
save_and_edit_next: Save and next.
|
@@ -245,6 +238,7 @@ en:
|
|
245
238
|
updater_id: 'Updater'
|
246
239
|
remember_me: Remember
|
247
240
|
password: Password
|
241
|
+
otp_attempt: OTP
|
248
242
|
flash:
|
249
243
|
admin:
|
250
244
|
actions:
|
@@ -290,5 +284,6 @@ en:
|
|
290
284
|
size_too_big: is too big (should be at most %{file_size})
|
291
285
|
carrierwave_processing_error: Cannot resize image.
|
292
286
|
carrierwave_integrity_error: Not an image.
|
287
|
+
changed: 'Record was changed by someone else, "Refresh" to get the latest version and repeat changes or "Force save" to overwrite'
|
293
288
|
unauthorized:
|
294
289
|
default: You are not authorized to access this page.
|
data/config/locales/it.yml
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
class CreateUsers < ActiveRecord::Migration
|
1
|
+
class CreateUsers < ActiveRecord::Migration[5.2]
|
2
2
|
def change
|
3
3
|
create_table(:users) do |t|
|
4
4
|
t.string :login
|
@@ -35,9 +35,6 @@ class CreateUsers < ActiveRecord::Migration
|
|
35
35
|
t.string :current_sign_in_ip
|
36
36
|
t.string :last_sign_in_ip
|
37
37
|
|
38
|
-
## Encryptable
|
39
|
-
t.string :password_salt
|
40
|
-
|
41
38
|
## Confirmable
|
42
39
|
t.string :confirmation_token
|
43
40
|
t.datetime :confirmed_at
|
@@ -1,12 +1,12 @@
|
|
1
|
-
class CreateHeaders < ActiveRecord::Migration
|
1
|
+
class CreateHeaders < ActiveRecord::Migration[5.2]
|
2
2
|
def change
|
3
3
|
create_table :headers do |t|
|
4
|
-
t.string
|
5
|
-
t.integer
|
6
|
-
|
4
|
+
t.string :headerable_type, limit: 50, null: false
|
5
|
+
t.integer :headerable_id, null: false
|
6
|
+
|
7
7
|
t.timestamps
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
add_index :headers, [:headerable_type, :headerable_id], unique: true
|
11
11
|
end
|
12
12
|
end
|
@@ -1,14 +1,11 @@
|
|
1
|
-
class CreateStaticPages < ActiveRecord::Migration
|
1
|
+
class CreateStaticPages < ActiveRecord::Migration[5.2]
|
2
2
|
def change
|
3
3
|
create_table :static_pages do |t|
|
4
|
-
t.
|
4
|
+
t.references :structure, null: false
|
5
5
|
t.references :user
|
6
6
|
t.boolean :is_visible, default: true, null: false
|
7
7
|
|
8
8
|
t.timestamps
|
9
9
|
end
|
10
|
-
|
11
|
-
add_index :static_pages, :user_id
|
12
|
-
add_index :static_pages, :structure_id
|
13
10
|
end
|
14
11
|
end
|
@@ -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, :map, :modal_form, :show,
|
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
|
|
@@ -7,8 +7,7 @@ module AbAdmin
|
|
7
7
|
include ::CarrierWave::MiniMagick
|
8
8
|
include AbAdmin::Utils::EvalHelpers
|
9
9
|
|
10
|
-
class_attribute :
|
11
|
-
self.transliterate = true
|
10
|
+
class_attribute :human_filenames
|
12
11
|
self.human_filenames = true
|
13
12
|
|
14
13
|
attr_accessor :internal_identifier
|
@@ -25,41 +24,48 @@ module AbAdmin
|
|
25
24
|
|
26
25
|
process :set_model_info
|
27
26
|
|
28
|
-
def
|
29
|
-
"#{
|
27
|
+
def filename
|
28
|
+
"#{[human_part, secure_token].compact.join('_')}#{extension}"
|
30
29
|
end
|
31
30
|
|
32
|
-
def
|
33
|
-
|
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('_')
|
34
36
|
end
|
35
37
|
|
36
|
-
def
|
37
|
-
|
38
|
-
return secure_token unless version_name
|
39
|
-
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
|
40
40
|
end
|
41
41
|
|
42
|
-
def
|
43
|
-
|
42
|
+
def extension
|
43
|
+
File.extname(model.original_name).downcase
|
44
44
|
end
|
45
45
|
|
46
|
-
def
|
47
|
-
|
48
|
-
system_part = base_filename_part
|
49
|
-
human_filename_part = for_file.chomp(ext)
|
50
|
-
return "#{system_part || version_name}#{ext}" if human_filename_part == secure_token
|
51
|
-
system_part ? "#{human_filename_part}_#{system_part}#{ext}" : "#{human_filename_part}#{ext}"
|
46
|
+
def version_extension
|
47
|
+
webp? ? '.webp' : extension
|
52
48
|
end
|
53
49
|
|
54
|
-
def
|
55
|
-
|
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?}"
|
56
55
|
end
|
57
56
|
|
58
|
-
# use secure token in the filename for non processed image
|
59
57
|
def secure_token
|
60
58
|
model.data_secure_token ||= AbAdmin.friendly_token(20).downcase
|
61
59
|
end
|
62
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
|
+
|
63
69
|
def store_model_filename(record)
|
64
70
|
old_file_name = filename
|
65
71
|
new_file_name = model_filename(old_file_name, record)
|
@@ -67,69 +73,81 @@ module AbAdmin
|
|
67
73
|
rename_via_move(new_file_name)
|
68
74
|
end
|
69
75
|
|
70
|
-
|
71
|
-
|
72
|
-
def filename
|
73
|
-
internal_identifier || model.send("#{mounted_as}_file_name") || (store_filename && "#{secure_token}#{File.extname(store_filename).downcase}")
|
74
|
-
end
|
75
|
-
|
76
|
-
def write_internal_identifier(internal_identifier)
|
77
|
-
self.internal_identifier = internal_identifier
|
78
|
-
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)
|
79
78
|
end
|
80
79
|
|
81
|
-
# transliterate original filename
|
82
|
-
# allow to build custom filename
|
83
80
|
def model_filename(base_filename, record)
|
84
81
|
custom_file_name = model.build_filename(base_filename, record)
|
85
82
|
return unless custom_file_name
|
86
|
-
normalize_filename(custom_file_name)
|
83
|
+
normalize_filename(custom_file_name)
|
87
84
|
end
|
85
|
+
private :model_filename
|
88
86
|
|
89
87
|
def normalize_filename(raw_filename)
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
to_path = File.join(dir, v.full_filename(new_file_name))
|
103
|
-
next if from_path == to_path || !File.exists?(from_path)
|
104
|
-
moves << [from_path, to_path]
|
105
|
-
end
|
106
|
-
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)
|
107
100
|
end
|
108
|
-
|
109
|
-
write_internal_identifier new_file_name
|
110
|
-
model.send("write_#{mounted_as}_identifier")
|
111
|
-
retrieve_from_store!(new_file_name) if human_filenames
|
112
|
-
|
113
|
-
new_file_name
|
101
|
+
retrieve_from_store!(model.send("#{mounted_as}_file_name"))
|
114
102
|
end
|
115
103
|
|
116
|
-
private :write_internal_identifier, :store_filename, :model_filename
|
117
|
-
|
118
|
-
def rmagick_included?
|
119
|
-
self.class.included_modules.map(&:to_s).include?('CarrierWave::RMagick')
|
120
|
-
end
|
121
|
-
|
122
|
-
# prevent large number of subdirectories
|
123
104
|
def store_dir
|
124
105
|
str_id = model.id.to_s.rjust(4, '0')
|
125
106
|
[AbAdmin.uploads_dir, model.class.to_s.underscore, str_id[0..2], str_id[3..-1]].join('/')
|
126
107
|
end
|
127
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
|
+
|
128
146
|
# Strips out all embedded information from the image
|
129
147
|
# process :strip
|
130
148
|
#
|
131
149
|
def strip
|
132
|
-
|
150
|
+
minimagick! do |img|
|
133
151
|
img.strip
|
134
152
|
img = yield(img) if block_given?
|
135
153
|
img
|
@@ -143,7 +161,7 @@ module AbAdmin
|
|
143
161
|
percentage = normalize_param(percentage)
|
144
162
|
|
145
163
|
unless percentage.blank?
|
146
|
-
|
164
|
+
minimagick! do |img|
|
147
165
|
img.quality percentage.to_s
|
148
166
|
img = yield(img) if block_given?
|
149
167
|
img
|
@@ -159,7 +177,7 @@ module AbAdmin
|
|
159
177
|
|
160
178
|
unless degrees.blank?
|
161
179
|
manipulate! do |img|
|
162
|
-
|
180
|
+
self.class.included_modules.map(&:to_s).include?('CarrierWave::RMagick') ? img.rotate!(degrees.to_i) : img.rotate(degrees.to_s)
|
163
181
|
img = yield(img) if block_given?
|
164
182
|
img
|
165
183
|
end
|
@@ -175,7 +193,7 @@ module AbAdmin
|
|
175
193
|
geometry = normalize_param(geometry[0]) if geometry.size == 1
|
176
194
|
|
177
195
|
if geometry && geometry.size == 4
|
178
|
-
|
196
|
+
minimagick! do |img|
|
179
197
|
img.crop '%ix%i+%i+%i' % geometry
|
180
198
|
img = yield(img) if block_given?
|
181
199
|
img
|
@@ -184,7 +202,7 @@ module AbAdmin
|
|
184
202
|
end
|
185
203
|
|
186
204
|
def watermark(watermark_path, gravity='SouthEast')
|
187
|
-
|
205
|
+
minimagick! do |img|
|
188
206
|
resolved_path = watermark_path.is_a?(Symbol) ? send(watermark_path) : watermark_path
|
189
207
|
watermark_image = ::MiniMagick::Image.open(resolved_path)
|
190
208
|
img.composite(watermark_image) { |c| c.gravity gravity }
|
@@ -201,12 +219,7 @@ module AbAdmin
|
|
201
219
|
end
|
202
220
|
|
203
221
|
def dimensions
|
204
|
-
[
|
205
|
-
end
|
206
|
-
|
207
|
-
def magick
|
208
|
-
#@magick ||= ::MiniMagick::Image.new(current_path)
|
209
|
-
::MiniMagick::Image.new(current_path)
|
222
|
+
[width, height]
|
210
223
|
end
|
211
224
|
|
212
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,14 +4,25 @@ 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
|
|
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) }
|
22
|
+
end
|
23
|
+
res.compact.max
|
24
|
+
end
|
25
|
+
|
15
26
|
def for_input_token
|
16
27
|
{id: id, text: AbAdmin.safe_display_name(self).to_s}
|
17
28
|
end
|
@@ -63,6 +74,13 @@ module AbAdmin
|
|
63
74
|
sql = "(#{quoted_order_col} #{predicate} :val OR (#{quoted_order_col} = :val AND #{self.class.quote_column('id')} #{id_predicate} #{id}))"
|
64
75
|
scope.where(sql, val: send(order_col)).ransack(query[:q]).result(distinct: true).first
|
65
76
|
end
|
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
|
66
84
|
end
|
67
85
|
end
|
68
86
|
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
|
data/lib/ab_admin/config/base.rb
CHANGED
@@ -32,6 +32,11 @@ module AbAdmin
|
|
32
32
|
|
33
33
|
class Table < BaseBuilder
|
34
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
|
35
40
|
end
|
36
41
|
|
37
42
|
class Search < BaseBuilder
|
@@ -42,6 +47,10 @@ module AbAdmin
|
|
42
47
|
self.partial_name = 'chart'
|
43
48
|
end
|
44
49
|
|
50
|
+
class Stats < BaseBuilder
|
51
|
+
self.partial_name = 'stats'
|
52
|
+
end
|
53
|
+
|
45
54
|
class Map < BaseBuilder
|
46
55
|
self.partial_name = 'map'
|
47
56
|
end
|
@@ -118,7 +127,7 @@ module AbAdmin
|
|
118
127
|
end
|
119
128
|
|
120
129
|
class BatchAction
|
121
|
-
attr_reader :name, :options, :data, :
|
130
|
+
attr_reader :name, :options, :data, :form
|
122
131
|
|
123
132
|
def initialize(name, options={}, &block)
|
124
133
|
@name = name
|
@@ -126,10 +135,13 @@ module AbAdmin
|
|
126
135
|
if options.has_key?(:form)
|
127
136
|
@form = options[:form].is_a?(String) ? options[:form] : "##{name}_batch_form"
|
128
137
|
end
|
129
|
-
@title = options[:title] || I18n.t("admin.actions.batch_#{name}.link", default: name.to_s.humanize)
|
130
138
|
@data = block_given? ? block : name.to_sym
|
131
139
|
end
|
132
140
|
|
141
|
+
def title
|
142
|
+
options[:title] || I18n.t("admin.actions.#{name}.title", default: name.to_s.humanize)
|
143
|
+
end
|
144
|
+
|
133
145
|
def confirm
|
134
146
|
options[:confirm]
|
135
147
|
end
|
@@ -176,8 +188,12 @@ module AbAdmin
|
|
176
188
|
@data = block
|
177
189
|
end
|
178
190
|
|
179
|
-
def
|
180
|
-
|
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)
|
181
197
|
end
|
182
198
|
end
|
183
199
|
end
|
@@ -1,11 +1,6 @@
|
|
1
1
|
class String
|
2
2
|
def no_html
|
3
|
-
|
4
|
-
str.gsub!(/<br\/?>/, ' ')
|
5
|
-
str.gsub!(/<\/?[^>]*>/, '')
|
6
|
-
str.strip!
|
7
|
-
str.gsub!(' ', ' ')
|
8
|
-
str
|
3
|
+
self.dup.gsub(/<br\/?>/, ' ').gsub(/<\/?[^>]*>/, '').strip.gsub(' ', ' ').gsub('>', '>').gsub('<', '<')
|
9
4
|
end
|
10
5
|
end
|
11
6
|
|