binda 0.0.3 → 0.0.5

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 (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +14 -29
  3. data/Rakefile +16 -10
  4. data/app/assets/javascripts/binda/components/form_item.js +12 -1
  5. data/app/assets/javascripts/binda/components/form_item_asset.js +1 -0
  6. data/app/assets/javascripts/binda/components/form_item_choice.js +58 -0
  7. data/app/assets/javascripts/binda/components/form_item_editor.js +39 -0
  8. data/app/assets/javascripts/binda/components/form_item_repeater.js +7 -0
  9. data/app/assets/javascripts/binda/components/sortable.js +0 -1
  10. data/app/assets/javascripts/binda/dist/binda.bundle.js +175 -8
  11. data/app/assets/javascripts/binda/index.js +4 -0
  12. data/app/assets/stylesheets/binda/components/form_item.scss +64 -2
  13. data/app/controllers/binda/application_controller.rb +2 -10
  14. data/app/controllers/binda/choices_controller.rb +19 -0
  15. data/app/controllers/binda/components_controller.rb +38 -134
  16. data/app/controllers/binda/field_groups_controller.rb +18 -30
  17. data/app/controllers/binda/structures_controller.rb +6 -6
  18. data/app/controllers/concerns/binda/component_controller_helper.rb +16 -0
  19. data/app/models/binda/checkbox.rb +7 -0
  20. data/app/models/binda/choice.rb +11 -0
  21. data/app/models/binda/component.rb +12 -136
  22. data/app/models/binda/field_group.rb +1 -1
  23. data/app/models/binda/field_setting.rb +40 -8
  24. data/app/models/binda/radio.rb +5 -0
  25. data/app/models/binda/repeater.rb +11 -79
  26. data/app/models/binda/select.rb +7 -0
  27. data/app/models/binda/structure.rb +13 -13
  28. data/app/models/concerns/binda/component_model_helper.rb +170 -0
  29. data/app/views/binda/components/_form_item_new_repeater.html.erb +3 -5
  30. data/app/views/binda/components/_form_item_selectable.html.erb +72 -0
  31. data/app/views/binda/components/_form_section.html.erb +7 -2
  32. data/app/views/binda/components/_form_section_repeater.html.erb +10 -0
  33. data/app/views/binda/field_groups/_form_item.html.erb +54 -26
  34. data/app/views/binda/field_groups/_form_item_choice.erb +96 -0
  35. data/app/views/binda/field_groups/_form_section.html.erb +2 -2
  36. data/app/views/binda/field_groups/_form_section_repeater.html.erb +2 -2
  37. data/config/locales/en.yml +7 -0
  38. data/config/routes.rb +2 -1
  39. data/db/migrate/1_create_binda_tables.rb +17 -0
  40. data/lib/binda/engine.rb +6 -0
  41. data/lib/binda/version.rb +1 -1
  42. data/lib/generators/binda/install/install_generator.rb +6 -8
  43. data/lib/generators/binda/setup/setup_generator.rb +8 -4
  44. metadata +66 -42
  45. data/app/controllers/binda/dates_controller.rb +0 -62
  46. data/app/controllers/binda/texts_controller.rb +0 -62
  47. data/app/views/binda/dates/_form.html.erb +0 -22
  48. data/app/views/binda/dates/edit.html.erb +0 -6
  49. data/app/views/binda/dates/index.html.erb +0 -27
  50. data/app/views/binda/dates/new.html.erb +0 -5
  51. data/app/views/binda/dates/show.html.erb +0 -9
  52. data/app/views/binda/repeaters/_form.html.erb +0 -27
  53. data/app/views/binda/repeaters/edit.html.erb +0 -6
  54. data/app/views/binda/repeaters/index.html.erb +0 -29
  55. data/app/views/binda/repeaters/new.html.erb +0 -5
  56. data/app/views/binda/repeaters/show.html.erb +0 -14
  57. data/app/views/binda/structures/add_child.html.erb +0 -0
  58. data/app/views/binda/texts/_form.html.erb +0 -22
  59. data/app/views/binda/texts/edit.html.erb +0 -6
  60. data/app/views/binda/texts/index.html.erb +0 -27
  61. data/app/views/binda/texts/new.html.erb +0 -5
  62. data/app/views/binda/texts/show.html.erb +0 -9
@@ -0,0 +1,16 @@
1
+ module Binda
2
+ module ComponentControllerHelper
3
+ extend ActiveSupport::Concern
4
+
5
+ def get_components( slug, ask_for_published = true, custom_order = '' )
6
+ if ask_for_published && custom_order.blank?
7
+ Binda::Structure.friendly.find( slug ).components.published.order('position')
8
+ elsif custom_order.blank?
9
+ Binda::Structure.friendly.find( slug ).components.order('position')
10
+ else
11
+ Binda::Structure.friendly.find( slug ).components.order( custom_order )
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,7 @@
1
+ module Binda
2
+ class Checkbox < Select
3
+
4
+ has_many :choices, as: :selectable
5
+
6
+ end
7
+ end
@@ -0,0 +1,11 @@
1
+ module Binda
2
+ class Choice < ApplicationRecord
3
+
4
+ belongs_to :field_setting
5
+ belongs_to :selectable, polymorphic: true, optional: true
6
+
7
+ validates :label, presence: true
8
+ validates :value, presence: true
9
+
10
+ end
11
+ end
@@ -1,18 +1,23 @@
1
1
  module Binda
2
2
  class Component < ApplicationRecord
3
3
 
4
+ include ComponentModelHelper
5
+
4
6
  # Associations
5
7
  belongs_to :structure, required: true
6
8
  has_and_belongs_to_many :categories
7
- has_many :texts, as: :fieldable, dependent: :delete_all
8
- has_many :dates, as: :fieldable, dependent: :delete_all
9
- has_many :galleries, as: :fieldable, dependent: :delete_all
10
- has_many :assets, as: :fieldable, dependent: :delete_all
9
+ has_many :texts, as: :fieldable, dependent: :delete_all
10
+ has_many :dates, as: :fieldable, dependent: :delete_all
11
+ has_many :galleries, as: :fieldable, dependent: :delete_all
12
+ has_many :assets, as: :fieldable, dependent: :delete_all
13
+ has_many :radios, as: :fieldable, dependent: :delete_all
14
+ has_many :selects, as: :fieldable, dependent: :delete_all
15
+ has_many :checkboxes, as: :fieldable, dependent: :delete_all
11
16
  # Repeaters need destroy_all, not delete_all
12
17
  has_many :repeaters, as: :fieldable, dependent: :destroy
13
18
 
14
19
 
15
- accepts_nested_attributes_for :structure, :categories, :texts, :dates, :assets, :galleries, :repeaters, allow_destroy: true
20
+ accepts_nested_attributes_for :structure, :categories, :texts, :dates, :assets, :galleries, :repeaters, :radios, :selects, :checkboxes, allow_destroy: true
16
21
 
17
22
  cattr_accessor :field_settings_array
18
23
 
@@ -47,140 +52,11 @@ module Binda
47
52
 
48
53
 
49
54
  # CUSTOM METHODS
50
- # --------------
51
- # https://github.com/norman/friendly_id/issues/436
55
+ #
56
+ # @see https://github.com/norman/friendly_id/issues/436
52
57
  def should_generate_new_friendly_id?
53
58
  slug.blank?
54
59
  end
55
-
56
- def find_or_create_a_field_by field_setting_id, field_type
57
- if Binda::FieldSetting.get_fieldables.include?( field_type.capitalize ) && field_setting_id.is_a?( Integer )
58
- self.send( field_type.pluralize ).find_or_create_by( field_setting_id: field_setting_id )
59
- else
60
- raise ArgumentError, "A parameter of the method 'find_or_create_a_field_by' is not correct.", caller
61
- end
62
- end
63
-
64
- def get_text( field_slug )
65
- # Get the object related to that field setting
66
- self.texts.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }.content
67
- end
68
-
69
- def has_text( field_slug )
70
- # Get the object related to that field setting
71
- obj = self.texts.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
72
- if obj.present?
73
- return !obj.content.blank?
74
- else
75
- return false
76
- end
77
- end
78
-
79
- def has_image( field_slug )
80
- # Check if the field has an attached image
81
- obj = self.assets.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }.image
82
- return obj.present?
83
- end
84
-
85
- def get_image_url( field_slug, size = '' )
86
- get_image_info( field_slug, size, 'url' )
87
- end
88
-
89
- def get_image_path( field_slug, size = '' )
90
- get_image_info( field_slug, size, 'path' )
91
- end
92
-
93
- def get_image_info( field_slug, size, info )
94
- # Get the object related to that field setting
95
- obj = self.assets.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
96
- if obj.image.present?
97
- if obj.image.respond_to?(size) && %w[thumb medium large].include?(size)
98
- obj.image.send(size).send(info)
99
- else
100
- obj.image.send(info)
101
- end
102
- end
103
- end
104
-
105
- def has_date( field_slug )
106
- # Check if the field has an attached date
107
- obj = self.dates.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
108
- if obj.present?
109
- return !obj.date.nil?
110
- else
111
- return false
112
- end
113
- end
114
-
115
- def get_date( field_slug )
116
- # Get the object related to that field setting
117
- self.dates.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }.date
118
- end
119
-
120
- def has_repeater( field_slug )
121
- obj = self.repeaters.find_all{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
122
- return obj.present?
123
- end
124
-
125
- def get_repeater( field_slug )
126
- self.repeaters.find_all{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }.sort_by(&:position)
127
- end
128
-
129
-
130
- # benchmark do
131
- # id = Binda::FieldSetting.field_settings_array.find { |fs| fs.slug == 'home-slides-project-image' }.id
132
- # obj = slide.assets.find{ |t| t.field_setting_id == id }
133
- # if obj.image.present?
134
- # if obj.image.respond_to?('') && %w[thumb medium large].include?('')
135
- # obj.image.send('').send('path')
136
- # else
137
- # obj.image.send('path')
138
- # end
139
- # end
140
- # end
141
-
142
- # BENCHMARK GET_IMAGE METHODS
143
- # ---------------------------
144
- # def get_image_benchmark( field_slug, size, info )
145
- # # Best is to run this group of test alone (i.e. without TestA and TestB)
146
- #
147
- # obj = self.assets.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
148
- #
149
- # self.class.benchmark("Check if image is present") do
150
- # obj.image.present?
151
- # end
152
- # self.class.benchmark("Check if file exists") do
153
- # obj.image.file.exists?
154
- # end
155
- # self.class.benchmark("Check if image respond to size") do
156
- # obj.image.respond_to?(size)
157
- # end
158
- # self.class.benchmark("Check if size is in array") do
159
- # %w[thumb medium large].include?(size)
160
- # end
161
- # if %w[thumb medium large].include?(size)
162
- # self.class.benchmark("get resized image") do
163
- # obj.image.send(size).send(info)
164
- # end
165
- # else
166
- # self.class.benchmark("get default image") do
167
- # obj.image.send(info)
168
- # end
169
- # end
170
-
171
- # # Run TestA and TestB separately not one after the other
172
- # # as the first time carrierwave runs is slower than the second time
173
- # self.class.benchmark("TestA: Get image info (url)") do
174
- # get_image_info( field_slug, size, 'url' )
175
- # end
176
- # self.class.benchmark("TestB: Get image info (path)") do
177
- # get_image_info( field_slug, size, 'path' )
178
- # end
179
-
180
- # self.class.benchmark("Get field setting id") do
181
- # self.assets.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
182
- # end
183
- # end
184
60
 
185
61
  end
186
62
  end
@@ -12,7 +12,7 @@ module Binda
12
12
  validates :name, presence: true
13
13
  validates :slug, uniqueness: true
14
14
  accepts_nested_attributes_for :field_settings, allow_destroy: true, reject_if: :is_rejected
15
-
15
+
16
16
  # Slug
17
17
  extend FriendlyId
18
18
  friendly_id :default_slug, use: [:slugged, :finders]
@@ -3,11 +3,10 @@ module Binda
3
3
 
4
4
  # Associations
5
5
  belongs_to :field_group
6
- # has_many :field_children, class_name: ::Binda::FieldSetting, dependent: :delete_all
7
6
  has_ancestry orphan_strategy: :destroy
8
7
 
9
8
  # Fields Associations
10
- # -------------------
9
+ #
11
10
  # If you add a new field remember to update:
12
11
  # - get_fieldables (see here below)
13
12
  # - get_field_types (see here below)
@@ -17,6 +16,10 @@ module Binda
17
16
  has_many :galleries, as: :fieldable
18
17
  has_many :assets, as: :fieldable
19
18
  has_many :repeater, as: :fieldable
19
+ has_many :radio, as: :fieldable
20
+ has_many :select, as: :fieldable
21
+ has_many :checkbox, as: :fieldable
22
+
20
23
 
21
24
  # The following direct association is used to securely delete associated fields
22
25
  # Infact via `fieldable` the associated fields might not be deleted
@@ -25,18 +28,38 @@ module Binda
25
28
  has_many :dates, dependent: :delete_all
26
29
  has_many :galleries, dependent: :delete_all
27
30
  has_many :repeater, dependent: :delete_all
31
+ has_many :radio, dependent: :delete_all
32
+ has_many :select, dependent: :delete_all
33
+ has_many :checkbox, dependent: :delete_all
34
+
35
+ has_many :choices, dependent: :delete_all
36
+ has_one :default_choice, class_name: 'Binda::Choice', dependent: :delete
28
37
 
29
- # accepts_nested_attributes_for :children, allow_destroy: true, reject_if: :is_rejected
38
+ accepts_nested_attributes_for :choices, allow_destroy: true, reject_if: :is_rejected
39
+
40
+ def is_rejected( attributes )
41
+ attributes['label'].blank? || attributes['content'].blank?
42
+ end
30
43
 
31
44
  cattr_accessor :field_settings_array
32
45
 
46
+ after_create do
47
+ self.class.reset_field_settings_array
48
+ end
49
+
50
+ after_destroy do
51
+ self.class.reset_field_settings_array
52
+ end
53
+
33
54
  def self.get_fieldables
34
- %w( Text Date Gallery Asset Repeater )
55
+ # TODO add 'Gallery' to this list
56
+ %w( Text Date Asset Repeater Radio Select Checkbox )
35
57
  end
36
58
 
37
59
  # Field types are't fieldable! watch out! They might use the same model (eg `string` and `text`)
38
60
  def get_field_types
39
- %w( string text asset gallery repeater date )
61
+ # TODO add 'gallery' to this list
62
+ %w( string text asset repeater date radio select checkbox )
40
63
  end
41
64
 
42
65
  # Validations
@@ -48,10 +71,10 @@ module Binda
48
71
  extend FriendlyId
49
72
  friendly_id :default_slug, use: [:slugged, :finders]
50
73
 
51
-
52
74
  # CUSTOM METHODS
53
- # --------------
54
- # https://github.com/norman/friendly_id/issues/436
75
+ #
76
+ # @see https://github.com/norman/friendly_id/issues/436
77
+
55
78
  def should_generate_new_friendly_id?
56
79
  slug.blank?
57
80
  end
@@ -77,6 +100,11 @@ module Binda
77
100
  return possible_names
78
101
  end
79
102
 
103
+ # Retrieve the ID if a slug is provided and update the field_settings_array
104
+ # in order to avoid calling the database (or the cached response) every time.
105
+ # This way Rails logs are much cleaner
106
+ #
107
+ # @return [integer] The ID of the field setting
80
108
  def self.get_id( field_slug )
81
109
  # Get field setting id from slug, without multiple calls to database
82
110
  # (the query runs once and caches the result, then any further call uses the cached result)
@@ -84,6 +112,10 @@ module Binda
84
112
  @@field_settings_array.find { |fs| fs.slug == field_slug }.id
85
113
  end
86
114
 
115
+ # Reset the field_settings_array. It's called every time
116
+ # the user creates or destroyes a Binda::FieldSetting
117
+ #
118
+ # @return [null]
87
119
  def self.reset_field_settings_array
88
120
  # Reset the result of the query taken with the above method,
89
121
  # this is needed when a user creates a new field_setting but
@@ -0,0 +1,5 @@
1
+ module Binda
2
+ class Radio < Select
3
+
4
+ end
5
+ end
@@ -1,13 +1,14 @@
1
1
  module Binda
2
2
  class Repeater < ApplicationRecord
3
3
 
4
+ include ComponentModelHelper
5
+
4
6
  # Associations
5
7
  belongs_to :fieldable, polymorphic: true
6
8
  belongs_to :field_setting
7
- # has_many :field_settings, dependent: :delete_all
8
9
 
9
10
  # Fields Associations
10
- # -------------------
11
+ #
11
12
  # If you add a new field remember to update:
12
13
  # - get_fieldables (see here below)
13
14
  # - get_field_types (see here below)
@@ -16,92 +17,23 @@ module Binda
16
17
  has_many :dates, as: :fieldable, dependent: :delete_all
17
18
  has_many :galleries, as: :fieldable, dependent: :delete_all
18
19
  has_many :assets, as: :fieldable, dependent: :delete_all
20
+ has_many :radios, as: :fieldable, dependent: :delete_all
21
+ has_many :selects, as: :fieldable, dependent: :delete_all
22
+ has_many :checkboxes, as: :fieldable, dependent: :delete_all
19
23
  # Repeaters need destroy_all, not delete_all
20
24
  has_many :repeaters, as: :fieldable, dependent: :destroy
21
25
 
22
- accepts_nested_attributes_for :texts, :dates, :assets, :galleries, :repeaters, allow_destroy: true
26
+ accepts_nested_attributes_for :texts, :dates, :assets, :galleries, :repeaters, :radios, :selects, :checkboxes, allow_destroy: true
23
27
 
24
28
  # The following direct association is used to securely delete associated fields
25
29
  # Infact via `fieldable` the associated fields might not be deleted
26
30
  # as the fieldable_id is related to the `component` rather than the `field_setting`
27
31
 
28
- # # Validations
29
- # validates :name, presence: true
30
-
31
- # # Slug
32
- # extend FriendlyId
33
- # friendly_id :default_slug, use: [:slugged, :finders]
34
-
35
- def find_or_create_a_field_by field_setting_id, field_type
36
- if Binda::FieldSetting.get_fieldables.include?( field_type.capitalize ) && field_setting_id.is_a?( Integer )
37
- self.send( field_type.pluralize ).find_or_create_by( field_setting_id: field_setting_id )
38
- else
39
- raise ArgumentError, "A parameter of the method 'find_or_create_a_field_by' is not correct.", caller
40
- end
41
- end
42
-
43
- def get_text( field_slug )
44
- # Get the object related to that field setting
45
- self.texts.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }.content
46
- end
47
-
48
- def has_text( field_slug )
49
- # Get the object related to that field setting
50
- obj = self.texts.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
51
- if obj.present?
52
- !obj.content.blank?
53
- else
54
- return false
55
- end
56
- end
57
-
58
- def has_image( field_slug )
59
- # Check if the field has an attached image
60
- self.assets.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }.image.present?
61
- end
62
-
63
- def get_image_url( field_slug, size = '' )
64
- get_image_info( field_slug, size, 'url' )
65
- end
66
-
67
- def get_image_path( field_slug, size = '' )
68
- get_image_info( field_slug, size, 'path' )
69
- end
70
-
71
- def get_image_info( field_slug, size, info )
72
- # Get the object related to that field setting
73
- obj = self.assets.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
74
- if obj.image.present?
75
- if obj.image.respond_to?(size) && %w[thumb medium large].include?(size)
76
- obj.image.send(size).send(info)
77
- else
78
- obj.image.send(info)
79
- end
80
- end
81
- end
82
-
83
- def has_date( field_slug )
84
- # Check if the field has an attached date
85
- obj = self.dates.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
86
- if obj.present?
87
- !obj.date.nil?
88
- else
89
- return false
90
- end
91
- end
92
-
93
- def get_date( field_slug )
94
- # Get the object related to that field setting
95
- self.dates.find{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }.date
96
- end
97
-
98
- def has_repeater( field_slug )
99
- obj = self.repeaters.find_all{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }
100
- return obj.present?
101
- end
32
+ after_create :set_default_position
102
33
 
103
- def get_repeater( field_slug )
104
- self.repeaters.find_all{ |t| t.field_setting_id == Binda::FieldSetting.get_id( field_slug ) }.sort_by(&:position)
34
+ def set_default_position
35
+ position = self.fieldable.repeaters.find_all{ |r| r.field_setting_id == self.field_setting.id }.length
36
+ self.update_attribute 'position', position
105
37
  end
106
38
 
107
39
  end
@@ -0,0 +1,7 @@
1
+ module Binda
2
+ class Select < ApplicationRecord
3
+
4
+ has_many :choices, as: :selectable
5
+
6
+ end
7
+ end