ab_admin 0.8.3 → 0.10.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 +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
|
@@ -3,44 +3,21 @@ module AbAdmin
|
|
|
3
3
|
module Callbacks
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
|
-
#included do
|
|
7
|
-
# define_admin_callbacks :build, :create, :update, :save, :destroy
|
|
8
|
-
#end
|
|
9
|
-
|
|
10
6
|
protected
|
|
11
7
|
|
|
12
|
-
def build_resource
|
|
13
|
-
object = get_resource_ivar || set_resource_ivar(end_of_association_chain.send(method_for_build, resource_params))
|
|
14
|
-
# run_build_callbacks object
|
|
15
|
-
object
|
|
16
|
-
end
|
|
17
|
-
|
|
18
8
|
def create_resource(object)
|
|
19
|
-
run_create_callbacks object
|
|
20
|
-
save_resource(object)
|
|
21
|
-
end
|
|
9
|
+
run_create_callbacks(object) {save_resource(object)}
|
|
22
10
|
end
|
|
23
11
|
|
|
24
12
|
def save_resource(object)
|
|
25
|
-
run_save_callbacks object
|
|
26
|
-
object.save
|
|
27
|
-
end
|
|
13
|
+
run_save_callbacks(object) {object.save}
|
|
28
14
|
end
|
|
29
15
|
|
|
30
16
|
def update_resource(object, attributes)
|
|
31
17
|
object.assign_attributes(attributes)
|
|
32
|
-
|
|
33
|
-
#run_update_callbacks object do
|
|
34
|
-
save_resource(object)
|
|
35
|
-
#end
|
|
18
|
+
save_resource(object)
|
|
36
19
|
end
|
|
37
20
|
|
|
38
|
-
#def destroy_resource(object)
|
|
39
|
-
# run_destroy_callbacks object do
|
|
40
|
-
# object.destroy
|
|
41
|
-
# end
|
|
42
|
-
#end
|
|
43
|
-
|
|
44
21
|
# Simple callback system. Implements before and after callbacks for
|
|
45
22
|
# use within the controllers.
|
|
46
23
|
#
|
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
class Array
|
|
2
|
-
def add_or_delete(el)
|
|
3
|
-
include?(el) ? delete(el) : push(el)
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
def word_count
|
|
7
|
-
each_with_object({}) do |word, h|
|
|
8
|
-
h[word] ||= 0
|
|
9
|
-
h[word] += 1
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
|
|
13
2
|
def deep_merge_hashes
|
|
14
3
|
self.inject({}) do |res, h|
|
|
15
4
|
raise Exception.new("Not a hash #{h}") unless h.is_a?(Hash)
|
|
@@ -22,30 +11,12 @@ class Array
|
|
|
22
11
|
inject(:+) / size
|
|
23
12
|
end
|
|
24
13
|
|
|
25
|
-
#def zip_all
|
|
26
|
-
# self[0].zip *self[1..-1]
|
|
27
|
-
#end
|
|
28
|
-
#
|
|
29
|
-
#def pluck!(method, *args)
|
|
30
|
-
# each_index { |x| self[x] = self[x].send method, *args }
|
|
31
|
-
#end
|
|
32
|
-
#
|
|
33
|
-
#alias invoke! pluck!
|
|
34
|
-
|
|
35
|
-
def without(*values)
|
|
36
|
-
copy = self.dup
|
|
37
|
-
copy.without!(*values)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
14
|
def without!(*values)
|
|
15
|
+
ActiveSupport::Deprecation.warn('Array#without! is deprecated without replacement')
|
|
41
16
|
values.flatten.each { |value| self.delete(value) }
|
|
42
17
|
self
|
|
43
18
|
end
|
|
44
19
|
|
|
45
|
-
def map_val(attr='id')
|
|
46
|
-
map{|el| el[attr] }
|
|
47
|
-
end
|
|
48
|
-
|
|
49
20
|
def contain?(other)
|
|
50
21
|
(other - self).empty?
|
|
51
22
|
end
|
|
@@ -53,24 +24,4 @@ class Array
|
|
|
53
24
|
def intersect?(other)
|
|
54
25
|
!(self & other).empty?
|
|
55
26
|
end
|
|
56
|
-
|
|
57
|
-
# def to_hash
|
|
58
|
-
# ActiveSupport::Deprecation.warn('Array#to_hash is deprecated, use Array#to_h or Hash[] instead')
|
|
59
|
-
# h = {}
|
|
60
|
-
# each { |k, v| h[k] = v }
|
|
61
|
-
# h
|
|
62
|
-
# end
|
|
63
|
-
|
|
64
|
-
def val_detect(attr, val)
|
|
65
|
-
detect{|v| v[attr] == val }
|
|
66
|
-
end
|
|
67
27
|
end
|
|
68
|
-
|
|
69
|
-
#module Enumerable
|
|
70
|
-
# def pluck(method, *args)
|
|
71
|
-
# map { |x| x.send method, *args }
|
|
72
|
-
# end
|
|
73
|
-
#
|
|
74
|
-
# alias invoke pluck
|
|
75
|
-
#end
|
|
76
|
-
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
class Hash
|
|
2
|
-
|
|
3
2
|
def reverse_deep_merge!(other_hash)
|
|
4
3
|
other_hash.each_pair do |k, v|
|
|
5
4
|
tv = self[k]
|
|
@@ -68,29 +67,13 @@ class Hash
|
|
|
68
67
|
end
|
|
69
68
|
end
|
|
70
69
|
|
|
71
|
-
def
|
|
72
|
-
if array.empty?
|
|
73
|
-
self
|
|
74
|
-
else
|
|
75
|
-
key = array.shift
|
|
76
|
-
value = self[key]
|
|
77
|
-
if array.empty?
|
|
78
|
-
value
|
|
79
|
-
elsif value.is_a? Hash
|
|
80
|
-
value.val(*array)
|
|
81
|
-
else
|
|
82
|
-
nil
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def store_multi(value, *keys)
|
|
70
|
+
def dig_store(value, *keys)
|
|
88
71
|
key = keys.shift
|
|
89
72
|
self[key] ||= {}
|
|
90
73
|
if keys.empty?
|
|
91
74
|
self[key] = value
|
|
92
75
|
else
|
|
93
|
-
self[key] = self[key].
|
|
76
|
+
self[key] = self[key].dig_store(value, *keys)
|
|
94
77
|
end
|
|
95
78
|
self
|
|
96
79
|
end
|
|
@@ -107,18 +90,6 @@ class Hash
|
|
|
107
90
|
reject { |_, v| v.blank? }
|
|
108
91
|
end
|
|
109
92
|
|
|
110
|
-
def no_blank
|
|
111
|
-
ActiveSupport::Deprecation.warn('`no_blank` is deprecated, use `reject_blank` instead')
|
|
112
|
-
reject_blank
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def try_keys(*try_keys)
|
|
116
|
-
try_keys.each do |k|
|
|
117
|
-
return self[k] if self.has_key?(k)
|
|
118
|
-
end
|
|
119
|
-
default
|
|
120
|
-
end
|
|
121
|
-
|
|
122
93
|
def deep_stringify_keys
|
|
123
94
|
inject({}) { |result, (key, value)|
|
|
124
95
|
value = value.deep_stringify_keys if value.is_a?(Hash)
|
|
@@ -1,91 +1,6 @@
|
|
|
1
1
|
class String
|
|
2
|
-
# http://lucene.apache.org/core/old_versioned_docs/versions/2_9_1/queryparsersyntax.html
|
|
3
|
-
#LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|`|"|~|\?|:|\\|\/)/
|
|
4
|
-
#LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|`|"|~|\?|:|\\|\s)/
|
|
5
|
-
|
|
6
|
-
KEYBOARDS = {
|
|
7
|
-
en: 'qwertyuiop[]asdfghjkl;\'zxcvbnm,./',
|
|
8
|
-
ru: 'йцукенгшщзхъфывапролджэячсмитьбю/'
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
unless defined? LUCENE_ESCAPE_REGEX
|
|
12
|
-
LUCENE_ESCAPE_REGEX = /(\+|-|&&|\|\||!|\(|\)|{|}|\[|\]|\^|"|~|\*|\?|:|\\|\/)/
|
|
13
|
-
|
|
14
|
-
def lucene_escape
|
|
15
|
-
self.gsub(LUCENE_ESCAPE_REGEX, "\\\\\\1")
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def capitalize_first
|
|
20
|
-
self.mb_chars[0].capitalize + self.mb_chars[1..-1]
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def is_int?
|
|
24
|
-
self =~ /^[-+]?[0-9]+$/
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def is_number?
|
|
28
|
-
self =~ /^[-+]?[0-9]+(\.[0-9]+)?$/
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
def to_utc
|
|
32
|
-
begin
|
|
33
|
-
Time.zone.parse(self).utc
|
|
34
|
-
rescue
|
|
35
|
-
Time.now.utc
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
2
|
def no_html
|
|
40
|
-
|
|
41
|
-
str.gsub!(/<br\/?>/, ' ')
|
|
42
|
-
str.gsub!(/<\/?[^>]*>/, '')
|
|
43
|
-
str.strip!
|
|
44
|
-
str.gsub!(' ', ' ')
|
|
45
|
-
str
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def tr_lang(from=nil, to=nil)
|
|
49
|
-
return '' if self.blank?
|
|
50
|
-
|
|
51
|
-
unless from || to
|
|
52
|
-
if KEYBOARDS[:en].index(self[0])
|
|
53
|
-
from, to = :en, :ru
|
|
54
|
-
elsif KEYBOARDS[:ru].index(self[0])
|
|
55
|
-
from, to = :ru, :en
|
|
56
|
-
else
|
|
57
|
-
from, to = :en, :ru
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
self.tr(KEYBOARDS[from], KEYBOARDS[to])
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def count_words
|
|
65
|
-
clean_text.scan(/(\p{Alnum}+([-'.]\p{Alnum}+)*)/u).size
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def words_count
|
|
69
|
-
frequencies = Hash.new(0)
|
|
70
|
-
downcase.scan(/(\w+([-'.]\w+)*)/) { |word, ignore| frequencies[word] += 1 }
|
|
71
|
-
frequencies
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def self.randomize(length = 8)
|
|
75
|
-
Array.new(length) { (rand(122-97) + 97).chr }.join
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def clean_text
|
|
79
|
-
coder = HTMLEntities.new
|
|
80
|
-
coder.decode(self.no_html)
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
def mb_upcase
|
|
84
|
-
mb_chars.upcase.to_s
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
def mb_downcase
|
|
88
|
-
mb_chars.downcase.to_s
|
|
3
|
+
self.dup.gsub(/<br\/?>/, ' ').gsub(/<\/?[^>]*>/, '').strip.gsub(' ', ' ').gsub('>', '>').gsub('<', '<')
|
|
89
4
|
end
|
|
90
5
|
end
|
|
91
6
|
|
data/lib/ab_admin/devise.rb
CHANGED
|
@@ -29,6 +29,13 @@ module AbAdmin
|
|
|
29
29
|
super
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
|
+
|
|
33
|
+
protected
|
|
34
|
+
|
|
35
|
+
def sign_in_params
|
|
36
|
+
devise_parameter_sanitizer.permit(:sign_in, keys: [:otp_attempt]) if devise_mapping.try(:two_factor_authenticatable?)
|
|
37
|
+
devise_parameter_sanitizer.sanitize(:sign_in)
|
|
38
|
+
end
|
|
32
39
|
end
|
|
33
40
|
|
|
34
41
|
class PasswordsController < ::Devise::PasswordsController
|
data/lib/ab_admin/engine.rb
CHANGED
|
@@ -2,7 +2,7 @@ module AbAdmin
|
|
|
2
2
|
class Engine < ::Rails::Engine
|
|
3
3
|
engine_name 'ab_admin'
|
|
4
4
|
|
|
5
|
-
initializer 'ab_admin.assets_precompile', :
|
|
5
|
+
initializer 'ab_admin.assets_precompile', group: :all do |app|
|
|
6
6
|
app.config.assets.precompile += AbAdmin.assets
|
|
7
7
|
end
|
|
8
8
|
|
|
@@ -19,6 +19,7 @@ module AbAdmin
|
|
|
19
19
|
ActiveRecord::Base.send :extend, AbAdmin::Concerns::Silencer
|
|
20
20
|
ActiveRecord::Base.send :include, AbAdmin::Concerns::Validations
|
|
21
21
|
ActiveRecord::Base.send :include, AbAdmin::Concerns::Fileuploads
|
|
22
|
+
ActiveRecord::Base.send :extend, AbAdmin::Concerns::TranslationsMacro
|
|
22
23
|
ActiveRecord::Base.send :extend, EnumField::EnumeratedAttribute
|
|
23
24
|
end
|
|
24
25
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'ckeditor'
|
|
3
|
+
|
|
4
|
+
Ckeditor::Utils.module_eval do
|
|
5
|
+
class << self
|
|
6
|
+
def js_replace(dom_id, options = nil)
|
|
7
|
+
options.present? ? "lazyInitCkeditor('#{dom_id}', #{ActiveSupport::JSON.encode(options)});" : "lazyInitCkEditor('#{dom_id}');"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
rescue LoadError => e
|
|
12
|
+
raise unless e.message.include?('ckeditor')
|
|
13
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require 'will_paginate/active_record'
|
|
2
|
+
|
|
1
3
|
# add `:large` option with make pagination on large tables easier, because `SELECT *` is slow with large `OFFSET`:
|
|
2
4
|
# first it fetch ids of the records using `SELECT id`
|
|
3
5
|
# and in the second query it fetch records
|
|
@@ -10,7 +12,7 @@ module WillPaginate
|
|
|
10
12
|
if value.nil?
|
|
11
13
|
paginate_limit || limit_value
|
|
12
14
|
else
|
|
13
|
-
limit(value)
|
|
15
|
+
limit(value.to_i)
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
|
|
@@ -18,7 +20,7 @@ module WillPaginate
|
|
|
18
20
|
if value.nil?
|
|
19
21
|
paginate_offset || offset_value
|
|
20
22
|
else
|
|
21
|
-
super(value)
|
|
23
|
+
super(value.to_i)
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
end
|
|
@@ -26,8 +28,8 @@ module WillPaginate
|
|
|
26
28
|
module Pagination
|
|
27
29
|
def paginate(options)
|
|
28
30
|
options = options.dup
|
|
29
|
-
page_number =
|
|
30
|
-
per_page = options.delete(:per_page) || self.per_page
|
|
31
|
+
page_number = [1, options[:page].to_i].max
|
|
32
|
+
per_page = (options.delete(:per_page) || self.per_page).to_i
|
|
31
33
|
total = options.delete(:total_entries)
|
|
32
34
|
large = options.delete(:large)
|
|
33
35
|
|
|
@@ -40,8 +42,8 @@ module WillPaginate
|
|
|
40
42
|
rel.total_entries = total.to_i unless total.blank?
|
|
41
43
|
|
|
42
44
|
if large
|
|
43
|
-
ids = rel.except(:includes).pluck(Arel.sql("#{quoted_table_name}
|
|
44
|
-
new_rel = rel.except(:limit, :offset, :where).where(
|
|
45
|
+
ids = rel.except(:includes).pluck(Arel.sql("#{quoted_table_name}.#{primary_key}"))
|
|
46
|
+
new_rel = rel.except(:limit, :offset, :where).where(primary_key => ids)
|
|
45
47
|
new_rel.paginate_limit = rel.limit_value.to_i
|
|
46
48
|
new_rel.paginate_offset = rel.offset_value.to_i
|
|
47
49
|
new_rel.total_entries = rel.total_entries
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# add `:no_uri` options to skip query params in pagination urls
|
|
2
1
|
require 'will_paginate/view_helpers/action_view'
|
|
3
2
|
|
|
3
|
+
# add `:no_uri` options to skip query params in pagination urls
|
|
4
4
|
WillPaginate::ViewHelpers.pagination_options[:no_uri] = false
|
|
5
5
|
WillPaginate::ActionView::LinkRenderer.class_exec do
|
|
6
6
|
def url(page)
|
|
@@ -19,7 +19,9 @@ module AbAdmin
|
|
|
19
19
|
|
|
20
20
|
if response.code == 200
|
|
21
21
|
json = MultiJson.decode(response)
|
|
22
|
-
json['data']['translations'][0]['translatedText']
|
|
22
|
+
res = json['data']['translations'][0]['translatedText'].to_s.gsub(/%\s{/, ' %{')
|
|
23
|
+
res = "#{res[0].upcase}#{res[1..-1]}" if text.first[/[[:upper:]]/]
|
|
24
|
+
res
|
|
23
25
|
else
|
|
24
26
|
raise StandardError, response.inspect
|
|
25
27
|
end
|
data/lib/ab_admin/menu/group.rb
CHANGED
|
@@ -10,9 +10,7 @@ module AbAdmin
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def render(template)
|
|
13
|
-
return
|
|
14
|
-
return if @options[:unless] && call_method_or_proc_on(template, @options[:unless])
|
|
15
|
-
|
|
13
|
+
return unless template.option_conditions_met?(@options)
|
|
16
14
|
wrapper_class = "dropdown-wrap-#{@raw_title}" if @raw_title.is_a?(Symbol)
|
|
17
15
|
<<-HTML.html_safe
|
|
18
16
|
<li class="dropdown #{wrapper_class}">
|
|
@@ -26,7 +24,7 @@ module AbAdmin
|
|
|
26
24
|
|
|
27
25
|
def title(template)
|
|
28
26
|
return @title unless @options[:badge]
|
|
29
|
-
badge =
|
|
27
|
+
badge = @options[:badge].is_a?(Symbol) ? template.public_send(@options[:badge]) : template.instance_exec(&@options[:badge])
|
|
30
28
|
return @title if !badge || badge == 0
|
|
31
29
|
"#{@title} <span class='badge badge-#{@options[:badge_type] || 'important'}'>#{badge}</span>".html_safe
|
|
32
30
|
end
|
data/lib/ab_admin/menu/item.rb
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
module AbAdmin
|
|
2
2
|
module Menu
|
|
3
3
|
class Item
|
|
4
|
-
include ::AbAdmin::Utils::EvalHelpers
|
|
5
|
-
|
|
6
4
|
def initialize(title, url, options)
|
|
7
5
|
@title = title.is_a?(Symbol) ? I18n.t(title, scope: [:admin, :navigation]) : title
|
|
8
6
|
@url = url
|
|
@@ -10,23 +8,21 @@ module AbAdmin
|
|
|
10
8
|
end
|
|
11
9
|
|
|
12
10
|
def render(template)
|
|
13
|
-
return
|
|
14
|
-
return if @options[:unless] && call_method_or_proc_on(template, @options[:unless])
|
|
11
|
+
return unless template.option_conditions_met?(@options)
|
|
15
12
|
|
|
16
|
-
item_url = @url.is_a?(String) ? @url :
|
|
13
|
+
item_url = @url.is_a?(String) ? @url : template.instance_exec(&@url)
|
|
17
14
|
active = template.request.path.split('/')[2] == item_url.split('/')[2]
|
|
18
15
|
|
|
19
16
|
<<-HTML.html_safe
|
|
20
|
-
<li class="#{'active' if active}">#{template.link_to title(template), item_url, @options.except(:if, :unless)}</li>
|
|
17
|
+
<li class="#{'active' if active}">#{template.link_to title(template), item_url, @options.except(:if, :unless, :badge)}</li>
|
|
21
18
|
HTML
|
|
22
19
|
end
|
|
23
20
|
|
|
24
21
|
private
|
|
25
22
|
|
|
26
23
|
def title(template)
|
|
27
|
-
ActiveSupport::Deprecation.warn('Menu item :badge_counter option is deprecated, use :badge instead') if @options[:badge_counter]
|
|
28
24
|
return @title unless @options[:badge]
|
|
29
|
-
badge =
|
|
25
|
+
badge = @options[:badge].is_a?(Symbol) ? template.public_send(@options[:badge]) : template.instance_exec(&@options[:badge])
|
|
30
26
|
return @title if !badge || badge == 0
|
|
31
27
|
"#{@title} <span class='badge badge-#{@options[:badge_type] || 'important'}'>#{badge}</span>".html_safe
|
|
32
28
|
end
|
|
@@ -30,7 +30,7 @@ module AbAdmin
|
|
|
30
30
|
|
|
31
31
|
def ext_list
|
|
32
32
|
return unless uploaders[:data]
|
|
33
|
-
uploaders[:data].new.
|
|
33
|
+
uploaders[:data].new.extension_allowlist
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
def clean!
|
|
@@ -76,14 +76,12 @@ module AbAdmin
|
|
|
76
76
|
AbAdmin.image_types.include?(self.data_content_type)
|
|
77
77
|
end
|
|
78
78
|
|
|
79
|
-
def
|
|
80
|
-
|
|
81
|
-
base == data_secure_token ? File.basename(original_name, '.*') : base
|
|
79
|
+
def human_filename
|
|
80
|
+
data.human_part
|
|
82
81
|
end
|
|
83
82
|
|
|
84
|
-
def
|
|
85
|
-
return
|
|
86
|
-
self.original_name = value + File.extname(data_file_name)
|
|
83
|
+
def human_filename=(value)
|
|
84
|
+
return if (human_filename.blank? && value.blank?) || human_filename == value
|
|
87
85
|
rename!(value)
|
|
88
86
|
end
|
|
89
87
|
|
|
@@ -116,14 +114,13 @@ module AbAdmin
|
|
|
116
114
|
|
|
117
115
|
def rename!(name=nil)
|
|
118
116
|
normalized_name = name ? data.normalize_filename(name) : rand(9999)
|
|
119
|
-
return
|
|
120
|
-
data.rename_via_move
|
|
117
|
+
return if normalized_name.blank?
|
|
118
|
+
data.rename_via_move normalized_name
|
|
121
119
|
end
|
|
122
120
|
|
|
123
121
|
def refresh_assetable
|
|
124
122
|
return unless assetable.try(:persisted?)
|
|
125
123
|
assetable.touch
|
|
126
|
-
assetable.tire.update_index if assetable.respond_to?(:tire)
|
|
127
124
|
true
|
|
128
125
|
end
|
|
129
126
|
|
|
@@ -24,12 +24,12 @@ module AbAdmin
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def normalize_html
|
|
27
|
-
|
|
27
|
+
AbAdmin.translated_locales.each do |loc|
|
|
28
28
|
%w(title h1 keywords description).each do |attr|
|
|
29
29
|
send("#{attr}_#{loc}=", send("#{attr}_#{loc}").to_s.no_html)
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
|
-
|
|
32
|
+
AbAdmin.translated_locales.each do |loc|
|
|
33
33
|
send("seo_block_#{loc}=", sanitize(send("seo_block_#{loc}").to_s))
|
|
34
34
|
end
|
|
35
35
|
end
|
|
@@ -58,12 +58,38 @@ module AbAdmin
|
|
|
58
58
|
csv_data.each do |d|
|
|
59
59
|
key_parts = [l.to_s] + d[0].split('.')
|
|
60
60
|
raise "Invalid key #{d[0]}" unless data.dig(*key_parts)
|
|
61
|
-
data.
|
|
61
|
+
data.dig_store(d[i], *key_parts)
|
|
62
62
|
end
|
|
63
63
|
save path, data
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
|
|
67
|
+
INTERPOLATION_REGEXP = /%{[^}]+}/
|
|
68
|
+
def csv_errors(csv)
|
|
69
|
+
return ['CSV blank'] if csv.blank?
|
|
70
|
+
csv_data = CSV.parse(csv)
|
|
71
|
+
errors = []
|
|
72
|
+
csv_data.shift.each_with_index do |l, i|
|
|
73
|
+
next if i.zero?
|
|
74
|
+
unless I18n.available_locales.include?(l.to_sym)
|
|
75
|
+
errors << "Unknown locale #{l}"
|
|
76
|
+
next
|
|
77
|
+
end
|
|
78
|
+
csv_data.each do |d|
|
|
79
|
+
key = d[0]
|
|
80
|
+
next if d[i].blank?
|
|
81
|
+
if translations.dig(I18n.default_locale, key)
|
|
82
|
+
unless translations.dig(I18n.default_locale, key).scan(INTERPOLATION_REGEXP).sort == d[i].scan(INTERPOLATION_REGEXP).sort
|
|
83
|
+
errors << "Wrong interpolations #{I18n.default_locale}:'#{translations.dig(I18n.default_locale, key)}' #{l}:#{d[i]}"
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
errors << "Extra interpolations #{l}:#{d[i]}" if d[i].scan(INTERPOLATION_REGEXP).present?
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
errors
|
|
91
|
+
end
|
|
92
|
+
|
|
67
93
|
def translations
|
|
68
94
|
@translations ||= I18n.backend.send(:translations).slice(*I18n.available_locales).transform_values{|v| v.flatten_hash.transform_keys{|k| k.join('.') } }
|
|
69
95
|
end
|
|
@@ -93,7 +119,7 @@ module AbAdmin
|
|
|
93
119
|
message = nil
|
|
94
120
|
locale_replace_regexp = Regexp.new("(^#{I18n.default_locale}|(?<=\.)#{I18n.default_locale}(?=\.yml))")
|
|
95
121
|
|
|
96
|
-
locale_files = @files.map { |path| self.class.prepare_data(path) }
|
|
122
|
+
locale_files = @files.find_all{|f| f =~ /\/\w+(\.readonly)?\.yml/ }.map { |path| self.class.prepare_data(path) }
|
|
97
123
|
main_locale_files = locale_files.find_all { |file| file.locale == I18n.default_locale }
|
|
98
124
|
|
|
99
125
|
main_locale_files.each do |main_file|
|
|
@@ -101,7 +127,7 @@ module AbAdmin
|
|
|
101
127
|
next if locale == I18n.default_locale
|
|
102
128
|
clean_locale_hash = main_file.data.deep_clear_values
|
|
103
129
|
path = File.join(main_file.dir, main_file.filename.sub(locale_replace_regexp, locale.to_s))
|
|
104
|
-
if File.
|
|
130
|
+
if File.exist?(path)
|
|
105
131
|
file = self.class.prepare_data(path)
|
|
106
132
|
self.class.save(path, {locale.to_s => clean_locale_hash.deep_add(file.data)})
|
|
107
133
|
else
|
|
@@ -38,7 +38,7 @@ module AbAdmin
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def read_data
|
|
41
|
-
paths = base_paths.dup.push(editable_path).compact.find_all { |path| File.
|
|
41
|
+
paths = base_paths.dup.push(editable_path).compact.find_all { |path| File.exist?(path) }
|
|
42
42
|
hash = paths.map{|path| YAML.safe_load(File.read(path)) }.inject(&:deep_merge).deep_symbolize_keys
|
|
43
43
|
SettingsStruct.new(hash)
|
|
44
44
|
end
|
|
@@ -53,7 +53,7 @@ module AbAdmin
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def editable_path
|
|
56
|
-
editable_paths.detect { |path| File.
|
|
56
|
+
editable_paths.detect { |path| File.exist?(path) }
|
|
57
57
|
end
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -15,12 +15,12 @@ module AbAdmin
|
|
|
15
15
|
validates_numericality_of :structure_type_id, only_integer: true
|
|
16
16
|
|
|
17
17
|
has_one :static_page, dependent: :destroy
|
|
18
|
-
has_many :visible_children, -> { where(is_visible: true) }, class_name: name, foreign_key:
|
|
18
|
+
has_many :visible_children, -> { where(is_visible: true) }, class_name: name, foreign_key: :parent_id
|
|
19
19
|
|
|
20
20
|
scope :visible, lambda { where(is_visible: true) }
|
|
21
|
-
scope :with_type, lambda { |
|
|
21
|
+
scope :with_type, lambda { |type| where(structure_type_id: (type.is_a?(Symbol) ? StructureType.public_send(type) : type.id)) }
|
|
22
22
|
scope :with_depth, lambda { |level| where(depth: level.to_i) }
|
|
23
|
-
scope :with_position, lambda { |
|
|
23
|
+
scope :with_position, lambda { |type| where(position_type_id: (type.is_a?(Symbol) ? StructureType.public_send(type) : type.id)).order(lft: :desc) }
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def redirect?
|
|
@@ -44,9 +44,9 @@ module AbAdmin
|
|
|
44
44
|
lookups << ['actions', key]
|
|
45
45
|
end
|
|
46
46
|
lookups.map!{|l| l.join('.').to_sym }
|
|
47
|
-
lookups <<
|
|
47
|
+
lookups << parts.last.humanize
|
|
48
48
|
|
|
49
|
-
I18n.t(lookups.shift, (parameters.merge(params) || {}).merge(scope: :admin, default: lookups))
|
|
49
|
+
I18n.t(lookups.shift, **(parameters.merge(params) || {}).merge(scope: :admin, default: lookups))
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def trackable_changed_attrs
|
|
@@ -63,7 +63,19 @@ module AbAdmin
|
|
|
63
63
|
|
|
64
64
|
def make_trackable
|
|
65
65
|
self.name ||= trackable.han.first(250)
|
|
66
|
-
self.trackable_changes = trackable.saved_changes.except(:updated_at)
|
|
66
|
+
self.trackable_changes = format_trackable_changes(trackable.saved_changes.except(:updated_at))
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def format_trackable_changes(value)
|
|
70
|
+
value.to_h.deep_transform_values do |v|
|
|
71
|
+
if v.is_a?(BigDecimal)
|
|
72
|
+
v.to_f
|
|
73
|
+
elsif v.is_a?(ActiveSupport::TimeWithZone)
|
|
74
|
+
v.to_s
|
|
75
|
+
else
|
|
76
|
+
v
|
|
77
|
+
end
|
|
78
|
+
end
|
|
67
79
|
end
|
|
68
80
|
end
|
|
69
81
|
end
|