ab_admin 0.1.2 → 0.2.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 (95) hide show
  1. data/Gemfile +1 -0
  2. data/Guardfile +1 -1
  3. data/app/assets/images/admin/flags/b_uk.png +0 -0
  4. data/app/assets/images/admin/preloader.gif +0 -0
  5. data/app/assets/javascripts/ab_admin/application.js +1 -28
  6. data/app/assets/javascripts/ab_admin/components/admin_assets.js.coffee +29 -6
  7. data/app/assets/javascripts/ab_admin/components/gmaps.js.coffee +120 -91
  8. data/app/assets/javascripts/ab_admin/components/google_translate.js.coffee +3 -2
  9. data/app/assets/javascripts/ab_admin/core/batch_actions.js.coffee +4 -7
  10. data/app/assets/javascripts/ab_admin/core/init.js.coffee +8 -10
  11. data/app/assets/javascripts/ab_admin/core/ui_utils.js.coffee +53 -24
  12. data/app/assets/javascripts/ab_admin/core/utils.js.coffee +7 -0
  13. data/app/assets/javascripts/ab_admin/inputs/datetime_input.js.coffee +1 -2
  14. data/app/assets/javascripts/ab_admin/main.js +28 -0
  15. data/app/assets/stylesheets/ab_admin/application.css.scss +1 -10
  16. data/app/assets/stylesheets/ab_admin/bootstrap_and_overrides.css.scss +4 -0
  17. data/app/assets/stylesheets/ab_admin/components/_base.css.scss +4 -1
  18. data/app/assets/stylesheets/ab_admin/components/_form.css.scss +10 -13
  19. data/app/assets/stylesheets/ab_admin/components/_geo_input.css.scss +5 -9
  20. data/app/assets/stylesheets/ab_admin/fileupload.css.scss +68 -102
  21. data/app/assets/stylesheets/ab_admin/main.css.scss +8 -0
  22. data/app/controllers/admin/base_controller.rb +18 -14
  23. data/app/controllers/admin/manager_controller.rb +51 -6
  24. data/app/controllers/admin/users_controller.rb +23 -0
  25. data/app/views/admin/fileupload/_asset.html.slim +8 -0
  26. data/app/views/admin/fileupload/_container.html.slim +10 -0
  27. data/app/views/admin/fileupload/_file.html.slim +5 -0
  28. data/app/views/admin/fileupload/_ftmpl.html.slim +6 -0
  29. data/app/views/admin/fileupload/_tmpl.html.slim +9 -0
  30. data/app/views/admin/users/_form.html.slim +1 -0
  31. data/config/locales/en.yml +5 -60
  32. data/config/locales/ru.yml +14 -63
  33. data/config/routes.rb +7 -4
  34. data/features/dsl/custom_actions.feature +62 -0
  35. data/features/dsl/parent_resource.feature +18 -0
  36. data/features/step_definitions/configuration_steps.rb +6 -0
  37. data/features/step_definitions/dsl/parent_resource_steps.rb +8 -0
  38. data/features/step_definitions/settings_steps.rb +1 -1
  39. data/features/step_definitions/web_steps/transforms_steps.rb +3 -0
  40. data/features/support/paths.rb +3 -0
  41. data/lib/ab_admin.rb +5 -0
  42. data/lib/ab_admin/abstract_resource.rb +28 -4
  43. data/lib/ab_admin/carrierwave/base_uploader.rb +22 -22
  44. data/lib/ab_admin/concerns/admin_addition.rb +2 -2
  45. data/lib/ab_admin/concerns/utilities.rb +4 -4
  46. data/lib/ab_admin/config/base.rb +18 -0
  47. data/lib/ab_admin/controllers/head_options.rb +1 -1
  48. data/lib/ab_admin/core_ext/array.rb +4 -0
  49. data/lib/ab_admin/core_ext/string.rb +9 -10
  50. data/lib/ab_admin/hooks/quiet_scope_page.rb +16 -16
  51. data/lib/ab_admin/hooks/simple_form_hooks.rb +13 -13
  52. data/lib/ab_admin/i18n_tools/model_translator.rb +67 -0
  53. data/lib/ab_admin/models/asset.rb +32 -1
  54. data/lib/ab_admin/models/attachment_file.rb +1 -1
  55. data/lib/ab_admin/models/locator.rb +7 -0
  56. data/lib/ab_admin/models/settings.rb +7 -0
  57. data/lib/ab_admin/models/structure.rb +4 -0
  58. data/lib/ab_admin/utils.rb +2 -2
  59. data/lib/ab_admin/version.rb +1 -1
  60. data/lib/ab_admin/views/admin_helpers.rb +3 -3
  61. data/lib/ab_admin/views/admin_navigation_helpers.rb +1 -1
  62. data/lib/ab_admin/views/form_builder.rb +42 -39
  63. data/lib/ab_admin/views/helpers.rb +5 -0
  64. data/lib/ab_admin/views/manager_helpers.rb +10 -0
  65. data/lib/ab_admin/views/search_form_builder.rb +12 -5
  66. data/lib/generators/ab_admin/install/install_generator.rb +1 -1
  67. data/lib/generators/ab_admin/install/templates/config/admin_menu.rb +2 -2
  68. data/lib/generators/ab_admin/install/templates/helpers/admin/structures_helper.rb +1 -1
  69. data/lib/generators/ab_admin/install/templates/models/attachment_file.rb +2 -0
  70. data/lib/generators/ab_admin/install/templates/models/locator.rb +0 -1
  71. data/lib/generators/ab_admin/install/templates/models/settings.rb +0 -1
  72. data/lib/generators/ab_admin/install/templates/models/static_page.rb +1 -0
  73. data/lib/generators/ab_admin/install/templates/{scripts → script}/unicorn.sh +0 -0
  74. data/lib/generators/ab_admin/install/templates/uploaders/avatar_uploader.rb +4 -0
  75. data/lib/generators/ab_admin/resource/templates/_search_form.haml.erb +1 -1
  76. data/lib/generators/ab_admin/resource/templates/_search_form.slim.erb +1 -1
  77. data/lib/generators/ab_admin/resource/templates/_table.haml.erb +1 -2
  78. data/lib/generators/ab_admin/resource/templates/_table.slim.erb +1 -2
  79. data/lib/generators/template.rb +1 -0
  80. data/lib/tasks/i18n.rake +7 -0
  81. data/spec/dummy/app/models/ab_admin/ab_admin_collection.rb +35 -0
  82. data/spec/dummy/app/models/ab_admin/ab_admin_product.rb +2 -0
  83. data/spec/dummy/app/models/admin_menu.rb +4 -2
  84. data/spec/dummy/app/models/collection.rb +3 -1
  85. data/spec/generators/install_generator_spec.rb +1 -1
  86. data/spec/generators/resource_generator_spec.rb +1 -1
  87. data/spec/models/avatar_spec.rb +29 -2
  88. metadata +25 -12
  89. data/app/views/admin/fileupload/_asset.html.erb +0 -5
  90. data/app/views/admin/fileupload/_container.html.erb +0 -28
  91. data/app/views/admin/fileupload/_fcontainer.html.erb +0 -25
  92. data/app/views/admin/fileupload/_file.html.erb +0 -5
  93. data/app/views/admin/fileupload/_ftmpl.html.erb +0 -7
  94. data/app/views/admin/fileupload/_tmpl.html.erb +0 -9
  95. data/lib/ab_admin/utils/csv_builder.rb +0 -52
@@ -4,10 +4,11 @@ module AbAdmin
4
4
 
5
5
  include Singleton
6
6
 
7
- ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy, :preview, :batch, :rebuild] unless self.const_defined?(:ACTIONS)
7
+ ACTIONS = [:index, :show, :new, :edit, :create, :update, :destroy, :preview, :batch, :rebuild, :custom_action] unless self.const_defined?(:ACTIONS)
8
8
 
9
9
  attr_accessor :table, :search, :export, :form, :show, :preview_path, :actions, :settings, :custom_settings,
10
- :batch_action_list, :action_items, :disabled_action_items, :resource_action_items, :tree_node_renderer
10
+ :batch_action_list, :action_items, :disabled_action_items, :resource_action_items, :tree_node_renderer,
11
+ :parent_resources, :custom_actions
11
12
 
12
13
  def initialize
13
14
  @actions = ACTIONS
@@ -16,6 +17,8 @@ module AbAdmin
16
17
  @disabled_action_items = []
17
18
  @default_action_items_for = {}
18
19
  @action_items_for = {}
20
+ @parent_resources = []
21
+ @custom_actions = []
19
22
  @model = self.class.name.sub('AbAdmin', '').safe_constantize
20
23
  add_admin_addition_to_model
21
24
  end
@@ -57,7 +60,7 @@ module AbAdmin
57
60
  ACTIONS - Array(options[:except]).map(&:to_sym)
58
61
  else
59
62
  actions_to_keep
60
- end
63
+ end << :custom_action
61
64
  end.map(&:to_sym)
62
65
  end
63
66
 
@@ -93,6 +96,21 @@ module AbAdmin
93
96
  def tree(&block)
94
97
  instance.tree_node_renderer = block
95
98
  end
99
+
100
+ def belongs_to(*args)
101
+ options = args.extract_options!
102
+ args.each do |name|
103
+ instance.parent_resources << OpenStruct.new(:name => name, :options => options)
104
+ end
105
+ end
106
+
107
+ def member_action(name, options={}, &block)
108
+ instance.custom_actions << AbAdmin::Config::CustomAction.new(name, options, &block)
109
+ end
110
+
111
+ def collection_action(name, options={}, &block)
112
+ instance.custom_actions << AbAdmin::Config::CustomAction.new(name, options.merge(:collection => true), &block)
113
+ end
96
114
  end
97
115
 
98
116
  def export
@@ -118,7 +136,13 @@ module AbAdmin
118
136
  end
119
137
 
120
138
  def resource_action_items
121
- @resource_action_items ||= [:edit, :show, :destroy, :preview]
139
+ @resource_action_items ||= [:edit, :show, :destroy, :preview] & @actions
140
+ end
141
+
142
+ def custom_action_for(name, context)
143
+ custom_action = @custom_actions.detect { |a| a.name == name.to_sym }
144
+ raise "No allowed custom action found #{name}" if !custom_action || !custom_action.for_context?(context)
145
+ custom_action
122
146
  end
123
147
 
124
148
  end
@@ -10,24 +10,24 @@ module AbAdmin
10
10
  include ::CarrierWave::MiniMagick
11
11
  include ::CarrierWave::MimeTypes
12
12
  include AbAdmin::Utils::EvalHelpers
13
-
13
+
14
14
  storage :file
15
-
15
+
16
16
  process :set_content_type
17
-
17
+
18
18
  with_options :if => :image? do |img|
19
19
  img.process :strip
20
20
  img.process :cropper => lambda { |model| model.cropper_geometry }
21
21
  img.process :rotate => lambda { |model| model.rotate_degrees }
22
22
  end
23
-
23
+
24
24
  process :set_model_info
25
-
26
- # default store assets path
25
+
26
+ # default store assets path
27
27
  def store_dir
28
28
  "uploads/#{model.class.to_s.underscore}/#{model.id}"
29
29
  end
30
-
30
+
31
31
  # Strips out all embedded information from the image
32
32
  # process :strip
33
33
  #
@@ -38,13 +38,13 @@ module AbAdmin
38
38
  img
39
39
  end
40
40
  end
41
-
41
+
42
42
  # Reduces the quality of the image to the percentage given
43
43
  # process :quality => 85
44
44
  #
45
45
  def quality(percentage)
46
46
  percentage = normalize_param(percentage)
47
-
47
+
48
48
  unless percentage.blank?
49
49
  manipulate! do |img|
50
50
  img.quality(percentage.to_s)
@@ -53,13 +53,13 @@ module AbAdmin
53
53
  end
54
54
  end
55
55
  end
56
-
56
+
57
57
  # Rotate image by degress
58
58
  # process :rotate => "-90"
59
59
  #
60
60
  def rotate(degrees = nil)
61
61
  degrees = normalize_param(degrees)
62
-
62
+
63
63
  unless degrees.blank?
64
64
  manipulate! do |img|
65
65
  img.rotate(degrees.to_s)
@@ -68,7 +68,7 @@ module AbAdmin
68
68
  end
69
69
  end
70
70
  end
71
-
71
+
72
72
  # Crop image by specific coordinates
73
73
  # http://www.imagemagick.org/script/command-line-processing.php?ImageMagick=6ddk6c680muj4eu2vr54vdveb7#geometry
74
74
  # process :cropper => [size, offset]
@@ -76,7 +76,7 @@ module AbAdmin
76
76
  #
77
77
  def cropper(*geometry)
78
78
  geometry = normalize_param(geometry[0]) if geometry.size == 1
79
-
79
+
80
80
  if geometry && geometry.size == 4
81
81
  manipulate! do |img|
82
82
  img.crop '%ix%i+%i+%i' % geometry
@@ -86,10 +86,10 @@ module AbAdmin
86
86
  end
87
87
  end
88
88
 
89
- def watermark(path_to_file)
89
+ def watermark(path_to_file, gravity='SouthEast')
90
90
  manipulate! do |img|
91
91
  logo = ::MiniMagick::Image.open(path_to_file)
92
- img.composite(logo) { |c| c.gravity 'SouthEast' }
92
+ img.composite(logo) { |c| c.gravity gravity }
93
93
  end
94
94
  end
95
95
 
@@ -97,31 +97,31 @@ module AbAdmin
97
97
  image_name = [model.class.to_s.underscore, version_name].compact.join('_')
98
98
  "/assets/defaults/#{image_name}.png"
99
99
  end
100
-
100
+
101
101
  def image?(new_file = nil)
102
102
  (file || new_file).content_type.include? 'image'
103
103
  end
104
-
104
+
105
105
  def dimensions
106
106
  [magick[:width], magick[:height]]
107
107
  end
108
-
108
+
109
109
  def magick
110
110
  #@magick ||= ::MiniMagick::Image.new(current_path)
111
111
  ::MiniMagick::Image.new(current_path)
112
112
  end
113
-
113
+
114
114
  protected
115
-
115
+
116
116
  def set_model_info
117
117
  model.data_content_type = file.content_type
118
118
  model.data_file_size = file.size
119
-
119
+
120
120
  if image? && model.has_dimensions?
121
121
  model.width, model.height = dimensions
122
122
  end
123
123
  end
124
-
124
+
125
125
  def normalize_param(value)
126
126
  if value.is_a?(Proc) || value.is_a?(Method)
127
127
  evaluate_method(model, value, file)
@@ -5,8 +5,8 @@ module AbAdmin
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
- scope :admin, scoped
9
- scope :base, scoped
8
+ scope(:admin, scoped) unless respond_to?(:admin)
9
+ scope(:base, scoped) unless respond_to?(:base)
10
10
  scope :ids, lambda { |ids| where("#{quoted_table_name}.id IN (?)", AbAdmin.val_to_array(ids).push(0)) }
11
11
 
12
12
  class_attribute :batch_actions, :instance_writer => false
@@ -101,9 +101,9 @@ module AbAdmin
101
101
  end
102
102
  end
103
103
 
104
- def generate_guid(column=:guid)
104
+ def generate_token(column=:guid)
105
105
  loop do
106
- token = Devise.friendly_token
106
+ token = ::Devise.friendly_token
107
107
  break token unless to_adapter.find_first({column => token})
108
108
  end
109
109
  end
@@ -113,9 +113,9 @@ module AbAdmin
113
113
  "#{self.class.model_name.singular}_#{id}"
114
114
  end
115
115
 
116
- def generate_token(column)
116
+ def generate_token(column=:guid)
117
117
  begin
118
- self[column] = Devise.friendly_token
118
+ self[column] = ::Devise.friendly_token
119
119
  end while self.class.exists?(column => self[column])
120
120
  end
121
121
  end
@@ -126,5 +126,23 @@ module AbAdmin
126
126
  normalize_display_options!
127
127
  end
128
128
  end
129
+
130
+ class CustomAction
131
+ include AbAdmin::Config::OptionalDisplay
132
+
133
+ attr_reader :name, :options, :data
134
+
135
+ def initialize(name, options={}, &block)
136
+ raise 'Can not create member action without a block' unless block_given?
137
+ @name = name
138
+ @options = options
139
+ @data = block
140
+ normalize_display_options!
141
+ end
142
+
143
+ def collection?
144
+ options[:collection]
145
+ end
146
+ end
129
147
  end
130
148
  end
@@ -6,7 +6,7 @@ module AbAdmin
6
6
  def head_options(record, options = {})
7
7
  return if record.nil?
8
8
 
9
- options = { :spliter => Utils.title_spliter, :append_title => true }.merge(options)
9
+ options = { :spliter => AbAdmin.title_spliter, :append_title => true }.merge(options)
10
10
 
11
11
  header = options[:header] || (record.respond_to?(:header) ? record.header : nil)
12
12
 
@@ -1,4 +1,8 @@
1
1
  class Array
2
+ def add_or_delete(el)
3
+ include?(el) ? delete(el) : push(el)
4
+ end
5
+
2
6
  def word_count
3
7
  each_with_object({}) do |word, h|
4
8
  h[word] ||= 0
@@ -55,26 +55,25 @@ class String
55
55
  self.tr(keyboard[from], keyboard[to])
56
56
  end
57
57
 
58
+ def count_words
59
+ clean_text.scan(/(\p{Alnum}+([-'.]\p{Alnum}+)*)/u).size
60
+ end
61
+
58
62
  def words_count
59
63
  frequencies = Hash.new(0)
60
64
  downcase.scan(/(\w+([-'.]\w+)*)/) { |word, ignore| frequencies[word] += 1 }
61
- return frequencies
65
+ frequencies
62
66
  end
63
67
 
64
68
  def self.randomize(length = 8)
65
69
  Array.new(length) { (rand(122-97) + 97).chr }.join
66
70
  end
67
71
 
68
- end
69
-
70
- if Object.const_defined?(:HTMLEntities)
71
- require 'htmlentities'
72
- class String
73
- def clean_text
74
- coder = HTMLEntities.new
75
- coder.decode(self.no_html)
76
- end
72
+ def clean_text
73
+ coder = HTMLEntities.new
74
+ coder.decode(self.no_html)
77
75
  end
76
+
78
77
  end
79
78
 
80
79
  unless ''.respond_to?(:each)
@@ -1,16 +1,16 @@
1
- module ActiveRecord
2
- module Scoping
3
- module Named
4
- module ClassMethods
5
- def valid_scope_name?(name)
6
- silence_names = [:page, :visible, :un_visible, :admin, :base]
7
- if respond_to?(name, true) && !silence_names.include?(name.to_sym)
8
- logger.warn "Creating scope :#{name}. " \
9
- "Overwriting existing method #{self.name}.#{name}."
10
- end
11
- end
12
- end
13
- end
14
- end
15
- end
16
-
1
+ #module ActiveRecord
2
+ # module Scoping
3
+ # module Named
4
+ # module ClassMethods
5
+ # def valid_scope_name?(name)
6
+ # silence_names = [:page, :visible, :un_visible, :admin, :base]
7
+ # if respond_to?(name, true) && !silence_names.include?(name.to_sym)
8
+ # logger.warn "Creating scope :#{name}. " \
9
+ # "Overwriting existing method #{self.name}.#{name}."
10
+ # end
11
+ # end
12
+ # end
13
+ # end
14
+ # end
15
+ #end
16
+ #
@@ -1,4 +1,4 @@
1
- require 'simple_form'
1
+ #require 'simple_form'
2
2
 
3
3
  #module WrappedButton
4
4
  # def wrapped_button(*args, &block)
@@ -17,15 +17,15 @@ require 'simple_form'
17
17
  # end
18
18
  #end
19
19
  #SimpleForm::FormBuilder.send :include, WrappedButton
20
-
21
- ::SimpleForm::Inputs::CollectionRadioButtonsInput.class_exec do
22
- def item_wrapper_class
23
- "radio #{options.delete(:item_wrapper_class)}"
24
- end
25
- end
26
-
27
- ::SimpleForm::Inputs::CollectionCheckBoxesInput.class_exec do
28
- def item_wrapper_class
29
- "radio #{options.delete(:item_wrapper_class)}"
30
- end
31
- end
20
+ #
21
+ #::SimpleForm::Inputs::CollectionRadioButtonsInput.class_exec do
22
+ # def item_wrapper_class
23
+ # "radio #{options.delete(:item_wrapper_class) || 'inline'}"
24
+ # end
25
+ #end
26
+ #
27
+ #::SimpleForm::Inputs::CollectionCheckBoxesInput.class_exec do
28
+ # def item_wrapper_class
29
+ # "radio #{options.delete(:item_wrapper_class) || 'inline'}"
30
+ # end
31
+ #end
@@ -0,0 +1,67 @@
1
+ module AbAdmin
2
+ module I18nTools
3
+ class ModelTranslator
4
+
5
+ IGNORE_COLUMNS = %w(id reset_password_sent_at remember_created_at current_sign_in_at confirmation_token
6
+ reset_password_token password_salt failed_attempts)
7
+
8
+ def initialize
9
+ @locales = Globalize.available_locales
10
+ @models = AbAdmin.translate_models.map{|m| m.constantize }
11
+ @models_i18n_hash = {}
12
+ end
13
+
14
+ def make_hash
15
+ @locales.each do |locale|
16
+ I18n.with_locale(locale) do
17
+ @models_i18n_hash[locale] = {'activerecord' => {'attributes' => {}, 'models' => {}}}
18
+
19
+ models_hash = @models.each_with_object({}) do |model, h|
20
+ model_i18n = {
21
+ 'zero' => model.model_name.human(:count => 0),
22
+ 'one' => model.model_name.human(:count => 1),
23
+ 'few' => (model.model_name.human(:count => 2) rescue model.model_name.human(:count => 1)),
24
+ 'many' => (model.model_name.human(:count => 9) rescue model.model_name.human(:count => 1)),
25
+ 'other' => (model.model_name.human(:count => 9) rescue model.model_name.human(:count => 1))
26
+ }
27
+ @models_i18n_hash[locale]['activerecord']['models'][model.model_name.i18n_key.to_s]= model_i18n
28
+ attributes = model.columns.map(&:name)
29
+ attributes.concat(model.translated_attribute_names.map(&:to_s)) if model.translates?
30
+ attributes.reject! { |el| IGNORE_COLUMNS.include?(el) }
31
+ h[model.model_name.underscore] = attributes.each_with_object({}) do |attr, o|
32
+ o[attr] = ha(model, attr, locale).presence || attr
33
+ model.reflect_on_all_associations.map(&:name).map(&:to_s).reject { |a| a =~ /^translation/ }.each do |assoc|
34
+ o[assoc] = ha(model, assoc, locale)
35
+ end
36
+ if model.new.respond_to?("#{attr}_#{locale.to_s}".to_sym)
37
+ @locales.each do |locale_1|
38
+ o["#{attr}_#{locale_1.to_s}"] = "#{ha(model, attr, locale)} (#{I18n.t(locale_1, :scope => [:attrs])})"
39
+ end
40
+ end
41
+ end.sort.to_hash
42
+ end
43
+ @models_i18n_hash[locale]['activerecord']['attributes'] = models_hash
44
+ end
45
+ end
46
+ end
47
+
48
+ def ha(model, attr, locale)
49
+ model.human_attribute_name(attr, :locale => locale)
50
+ end
51
+
52
+ def write_yaml
53
+ locale_dir = Rails.root.join('config/locales')
54
+ @locales.each do |locale|
55
+ Locator.save(locale_dir.join("#{locale}.attrs.yml"), {locale.to_s => @models_i18n_hash[locale]})
56
+ end
57
+ end
58
+
59
+ def self.i18n_models!
60
+ model_translator = new
61
+ model_translator.make_hash
62
+ model_translator.write_yaml
63
+ end
64
+
65
+ end
66
+ end
67
+ end