binda 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (132) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +83 -25
  3. data/app/assets/javascripts/binda/application.js +3 -3
  4. data/app/assets/javascripts/binda/components/bootstrap.js +3 -4
  5. data/app/assets/javascripts/binda/components/field_group_editor.js +10 -10
  6. data/app/assets/javascripts/binda/components/field_setting_choices.js +61 -49
  7. data/app/assets/javascripts/binda/components/fileupload.js +135 -118
  8. data/app/assets/javascripts/binda/components/form_item.js +65 -65
  9. data/app/assets/javascripts/binda/components/form_item_editor.js +19 -19
  10. data/app/assets/javascripts/binda/components/form_item_image.js +11 -13
  11. data/app/assets/javascripts/binda/components/form_item_repeater.js +77 -71
  12. data/app/assets/javascripts/binda/components/login-shader.js +171 -164
  13. data/app/assets/javascripts/binda/components/login_form.js +65 -73
  14. data/app/assets/javascripts/binda/components/radio-toggle.js +8 -12
  15. data/app/assets/javascripts/binda/components/select2.js +19 -14
  16. data/app/assets/javascripts/binda/components/sortable.js +76 -71
  17. data/app/assets/javascripts/binda/dist/binda.bundle.js +735 -727
  18. data/app/assets/javascripts/binda/index.js +49 -35
  19. data/app/assets/stylesheets/binda/components/assets_manager.scss +13 -22
  20. data/app/assets/stylesheets/binda/components/b-alert.scss +18 -14
  21. data/app/assets/stylesheets/binda/components/b-btn.scss +24 -43
  22. data/app/assets/stylesheets/binda/components/field_setting_choices.scss +16 -31
  23. data/app/assets/stylesheets/binda/components/fileupload.scss +25 -42
  24. data/app/assets/stylesheets/binda/components/form_item.scss +51 -93
  25. data/app/assets/stylesheets/binda/components/form_item_choices.scss +7 -10
  26. data/app/assets/stylesheets/binda/components/login.scss +2 -2
  27. data/app/assets/stylesheets/binda/components/main_header.scss +5 -10
  28. data/app/assets/stylesheets/binda/components/main_sidebar.scss +42 -46
  29. data/app/assets/stylesheets/binda/components/main_sortable_table.scss +12 -21
  30. data/app/assets/stylesheets/binda/components/main_table.scss +18 -35
  31. data/app/assets/stylesheets/binda/components/popup_warning.scss +14 -27
  32. data/app/assets/stylesheets/binda/components/select2.scss +46 -48
  33. data/app/assets/stylesheets/binda/components/sortable.scss +25 -45
  34. data/app/assets/stylesheets/binda/components/standard-form.scss +43 -73
  35. data/app/assets/stylesheets/binda/controllers/users_sessions_new.scss +52 -89
  36. data/app/assets/stylesheets/binda/index.scss +0 -1
  37. data/app/assets/stylesheets/binda/settings/buttons.scss +9 -10
  38. data/app/assets/stylesheets/binda/settings/common.scss +17 -22
  39. data/app/assets/stylesheets/binda/settings/fonts.scss +112 -67
  40. data/app/assets/stylesheets/binda/settings/tiny_mce_overrides.scss +20 -36
  41. data/app/assets/stylesheets/binda/settings/variables.scss +38 -43
  42. data/app/controllers/binda/choices_controller.rb +14 -11
  43. data/app/controllers/binda/components_controller.rb +6 -4
  44. data/app/controllers/binda/structures_controller.rb +7 -3
  45. data/app/helpers/binda/components_helper.rb +69 -3
  46. data/app/helpers/binda/field_groups_helper.rb +16 -6
  47. data/app/helpers/binda/structures_helper.rb +1 -4
  48. data/app/models/binda/application_record.rb +4 -1
  49. data/app/models/binda/asset.rb +3 -1
  50. data/app/models/binda/b.rb +1 -0
  51. data/app/models/binda/category.rb +1 -0
  52. data/app/models/binda/checkbox.rb +2 -0
  53. data/app/models/binda/choice.rb +74 -41
  54. data/app/models/binda/component.rb +1 -1
  55. data/app/models/binda/date.rb +4 -0
  56. data/app/models/binda/deprecation.rb +7 -0
  57. data/app/models/binda/field_group.rb +16 -3
  58. data/app/models/binda/field_setting.rb +168 -41
  59. data/app/models/binda/image.rb +1 -0
  60. data/app/models/binda/radio.rb +2 -0
  61. data/app/models/binda/relation.rb +3 -0
  62. data/app/models/binda/repeater.rb +3 -0
  63. data/app/models/binda/selection.rb +237 -0
  64. data/app/models/binda/string.rb +4 -0
  65. data/app/models/binda/structure.rb +25 -14
  66. data/app/models/binda/text.rb +9 -0
  67. data/app/models/binda/video.rb +1 -0
  68. data/app/models/concerns/binda/default_helpers.rb +40 -31
  69. data/app/models/concerns/binda/deprecations.rb +6 -0
  70. data/app/models/concerns/binda/fieldable_association_helpers.rb +366 -0
  71. data/app/models/concerns/binda/fieldable_associations.rb +32 -369
  72. data/app/views/binda/boards/edit.html.erb +15 -2
  73. data/app/views/binda/categories/_form.html.erb +24 -51
  74. data/app/views/binda/categories/edit.html.erb +23 -3
  75. data/app/views/binda/categories/index.html.erb +49 -25
  76. data/app/views/binda/categories/new.html.erb +21 -2
  77. data/app/views/binda/components/edit.html.erb +27 -4
  78. data/app/views/binda/components/index.html.erb +47 -50
  79. data/app/views/binda/components/new.html.erb +12 -2
  80. data/app/views/binda/components/sort_index.html.erb +28 -13
  81. data/app/views/binda/field_groups/_form_body.html.erb +43 -82
  82. data/app/views/binda/field_groups/_form_item.html.erb +3 -120
  83. data/app/views/binda/field_groups/_form_section.html.erb +11 -16
  84. data/app/views/binda/field_groups/_form_section_repeater.html.erb +7 -15
  85. data/app/views/binda/field_groups/edit.html.erb +14 -2
  86. data/app/views/binda/field_groups/form_item/_form_item_choice_editor.html.erb +11 -0
  87. data/app/views/binda/field_groups/form_item/_form_item_editor.html.erb +14 -0
  88. data/app/views/binda/field_groups/form_item/_form_item_header.html.erb +25 -0
  89. data/app/views/binda/field_groups/form_item/_form_item_new_editor.html.erb +8 -0
  90. data/app/views/binda/field_groups/form_item/_form_item_persisted_editor.html.erb +27 -0
  91. data/app/views/binda/field_groups/form_item/form_item_choice/_form_item_allow_null_choice.html.erb +11 -0
  92. data/app/views/binda/field_groups/form_item/form_item_choice/_form_item_choice_header.html.erb +11 -0
  93. data/app/views/binda/field_groups/form_item/form_item_choice/_form_item_default_choice.html.erb +11 -0
  94. data/app/views/binda/field_groups/form_item/form_item_choice/_form_item_new_choice.html.erb +16 -0
  95. data/app/views/binda/field_groups/form_item/form_item_choice/_form_item_persisted_choices.html.erb +16 -0
  96. data/app/views/binda/field_groups/new.html.erb +14 -2
  97. data/app/views/binda/field_settings/_form_body.html.erb +1 -3
  98. data/app/views/binda/field_settings/edit.html.erb +1 -1
  99. data/app/views/binda/field_settings/new.html.erb +1 -1
  100. data/app/views/binda/fieldable/_form_body.html.erb +24 -72
  101. data/app/views/binda/fieldable/_form_item_date.html.erb +1 -4
  102. data/app/views/binda/fieldable/_form_item_image.html.erb +3 -7
  103. data/app/views/binda/fieldable/_form_item_new_repeater.html.erb +0 -13
  104. data/app/views/binda/fieldable/_form_item_selections.html.erb +20 -112
  105. data/app/views/binda/fieldable/form_item_selections/_form_item_checkbox.html.erb +34 -0
  106. data/app/views/binda/fieldable/form_item_selections/_form_item_radio.html.erb +28 -0
  107. data/app/views/binda/fieldable/form_item_selections/_form_item_selection.html.erb +30 -0
  108. data/app/views/binda/manage/users/_form_body.html.erb +1 -31
  109. data/app/views/binda/manage/users/edit.html.erb +12 -2
  110. data/app/views/binda/manage/users/index.html.erb +36 -19
  111. data/app/views/binda/manage/users/new.html.erb +14 -3
  112. data/app/views/binda/structures/_form_body.html.erb +2 -25
  113. data/app/views/binda/structures/_form_section.html.erb +43 -65
  114. data/app/views/binda/structures/_form_sidebar.html.erb +19 -12
  115. data/app/views/binda/structures/edit.html.erb +20 -3
  116. data/app/views/binda/structures/index.html.erb +46 -26
  117. data/app/views/binda/structures/new.html.erb +13 -2
  118. data/app/views/binda/structures/sort_index.html.erb +37 -17
  119. data/app/views/binda/users/sessions/new.html.erb +25 -20
  120. data/app/views/layouts/binda/_form_errors.html.erb +10 -0
  121. data/app/views/layouts/binda/_sidebar.html.erb +6 -6
  122. data/app/views/layouts/binda/application.html.erb +1 -1
  123. data/config/initializers/carrierwave.rb +3 -2
  124. data/config/locales/en.yml +56 -12
  125. data/config/tinymce.yml +2 -2
  126. data/db/migrate/1_create_binda_tables.rb +1 -1
  127. data/lib/binda/version.rb +1 -1
  128. data/lib/generators/binda/setup/setup_generator.rb +2 -2
  129. data/lib/tasks/add_default_choice_to_all_selections_with_no_choices_task.rake +6 -0
  130. metadata +58 -8
  131. data/app/assets/stylesheets/binda/components/form_item_image.scss +0 -0
  132. data/app/views/binda/field_groups/_form_item_choice.erb +0 -104
@@ -1,4 +1,8 @@
1
1
  module Binda
2
+ # This class depends on `Binda::Text` and it's use mainly to differentiate the type of text
3
+ # this class is responsible for.
4
+ #
5
+ # Binda uses this class to store plain text. The field responsible to store `Binda::String` instances is `type="string"`.
2
6
  class String < Text
3
7
  end
4
8
  end
@@ -12,7 +12,11 @@ module Binda
12
12
  # Validations
13
13
  validates :name, presence: true
14
14
  validates :slug, uniqueness: true
15
- validates :instance_type, presence: true, inclusion: { in: %w(component board), message: "%{value} is not a valid instance" }
15
+ validates_associated :field_groups
16
+ validates :instance_type, presence: true, inclusion: {
17
+ in: %w(component board),
18
+ message: I18n.t('binda.structure.validation_message.instance_type', { arg1: "%{value}" })
19
+ }
16
20
  accepts_nested_attributes_for :field_groups, allow_destroy: true, reject_if: :is_rejected
17
21
 
18
22
  # Slug
@@ -20,7 +24,7 @@ module Binda
20
24
  friendly_id :default_slug, use: [:slugged, :finders]
21
25
 
22
26
  after_create :add_default_field_group
23
- after_create :add_instance_details
27
+ after_save :add_instance_details
24
28
  after_create :set_default_position
25
29
 
26
30
  # Friendly id preference on slug generation
@@ -28,12 +32,12 @@ module Binda
28
32
  # Method inherited from friendly id
29
33
  # @see https://github.com/norman/friendly_id/issues/436
30
34
  def should_generate_new_friendly_id?
31
- slug.blank? || name_changed?
35
+ slug.blank?
32
36
  end
33
37
 
34
38
  #
35
39
  # Sets the validation rules to accept and save an attribute
36
- def is_rejected( attributes )
40
+ def is_rejected(attributes)
37
41
  attributes['name'].blank?
38
42
  end
39
43
 
@@ -41,10 +45,10 @@ module Binda
41
45
  #
42
46
  # It generates 4 possible slugs before falling back to FriendlyId default behaviour
43
47
  def default_slug
44
- [ "#{ self.name }",
45
- "#{ self.name }-1",
46
- "#{ self.name }-2",
47
- "#{ self.name }-3" ]
48
+ [ "#{ self.name.parameterize }",
49
+ "#{ self.name.parameterize }-1",
50
+ "#{ self.name.parameterize }-2",
51
+ "#{ self.name.parameterize }-3" ]
48
52
  end
49
53
 
50
54
  # Add a field group as a default
@@ -54,10 +58,10 @@ module Binda
54
58
  # @return [redirect]
55
59
  def add_default_field_group
56
60
  # Creates a default empty field group
57
- field_group = self.field_groups.build( name: 'General Details', position: 1 )
61
+ field_group = self.field_groups.build(name: I18n.t('binda.default_field_group.name'), position: 1)
58
62
  # Unless there is a problem...
59
63
  unless field_group.save
60
- return redirect_to structure_path( self.slug ), flash: { error: 'General Details group hasn\'t been created' }
64
+ return redirect_to structure_path(self.slug), flash: { error: I18n.t('binda.default_field_group.error_on_create') }
61
65
  end
62
66
  end
63
67
 
@@ -68,10 +72,17 @@ module Binda
68
72
  # It also disable categories (this could be a different method, or method could be more explicit)
69
73
  def add_instance_details
70
74
  if self.instance_type == 'board'
71
- self.update_attribute 'has_categories', false
75
+ self.update_attribute('has_categories', false)
76
+ add_default_board
77
+ end
78
+ end
79
+
80
+ # Add default board to a structure if needed
81
+ def add_default_board
82
+ if Board.where(structure_id: self.id).empty?
72
83
  board = self.build_board( name: self.name )
73
84
  unless board.save
74
- return redirect_to structure_path( self.slug ), flash: { error: 'The board instance hasn\'t been created' }
85
+ return redirect_to structure_path(self.slug), flash: { error: I18n.t('binda.default_field_group.error_on_create') }
75
86
  end
76
87
  end
77
88
  end
@@ -83,8 +94,8 @@ module Binda
83
94
  #
84
95
  # @return [object] Repeater instance
85
96
  def set_default_position
86
- position = Structure.all.length
87
- self.update_attribute 'position', position
97
+ position = Structure.all.length
98
+ self.update_attribute('position', position)
88
99
  end
89
100
 
90
101
  end
@@ -1,9 +1,18 @@
1
1
  module Binda
2
+ # This class provides support for storing text. It can be called directly to get texts,
3
+ # or referenced to call other classes depending on it that deal differently with text.
4
+ #
5
+ # Binda uses this class to store complex texts usually with rich HTML features. On the admin panel infact
6
+ # this field is represented by a WYSIWYG. But this is just a admin panel convention: the class can infact store
7
+ # a simple string of text as well.
2
8
  class Text < ApplicationRecord
3
9
 
4
10
  # Associations
5
11
  belongs_to :fieldable, polymorphic: true
6
12
  belongs_to :field_setting
7
13
 
14
+ validates :fieldable_id, presence: true
15
+ validates :fieldable_type, presence: true
16
+
8
17
  end
9
18
  end
@@ -1,4 +1,5 @@
1
1
  module Binda
2
+ # This class provides support for uploading videos.
2
3
  class Video < Asset
3
4
 
4
5
  mount_uploader :video, VideoUploader
@@ -3,9 +3,6 @@ module Binda
3
3
  module DefaultHelpers
4
4
  extend ActiveSupport::Concern
5
5
 
6
- included do
7
- end
8
-
9
6
  class_methods do
10
7
 
11
8
  # Get components
@@ -35,14 +32,14 @@ module Binda
35
32
  # @param slug [string] The slug of the structure to which the components belong
36
33
  # @param slug [array] The slugs of the structures to which the components belongs
37
34
  #
38
- # @return [ActiveRelation Object] if slug is nil or is an array
35
+ # @return [ActiveRecord::Relation Object] if slug is nil or is an array
39
36
  #
40
- def get_components slug = nil
37
+ def get_components(slug = nil)
41
38
  if slug.nil?
42
39
  Component.all
43
40
  else
44
41
  # Generate query
45
- Component.where( structure_id: Structure.where( slug: slug ) )
42
+ Component.where(structure_id: Structure.where(slug: slug))
46
43
  end
47
44
  end
48
45
 
@@ -64,13 +61,13 @@ module Binda
64
61
  # @param slug [string] The slug of the structure on which the board is based
65
62
  # @param slug [array] The slugs of the structures to which the board belongs
66
63
  #
67
- # @return [ActiveRelation Object] if slug is nil or is an array
64
+ # @return [ActiveRecord::Relation Object] if slug is nil or is an array
68
65
  #
69
- def get_boards slug = nil
66
+ def get_boards(slug = nil)
70
67
  if slug.nil?
71
68
  Board.all
72
69
  else
73
- Board.where( structure_id: Structure.where( slug: slug ) )
70
+ Board.where(structure_id: Structure.where(slug: slug))
74
71
  end
75
72
  end
76
73
 
@@ -92,13 +89,13 @@ module Binda
92
89
  # @param slug [string] The slug of the structure to which categories belong
93
90
  # @param slug [array] The slugs of the structures to which categories belong
94
91
  #
95
- # @return [ActiveRelation Object]
92
+ # @return [ActiveRecord::Relation Object]
96
93
  #
97
- def get_categories slug = nil
94
+ def get_categories(slug = nil)
98
95
  if slug.nil?
99
96
  Category.all
100
97
  else
101
- Category.where( structure_id: Structure.where( slug: slug ) )
98
+ Category.where(structure_id: Structure.where(slug: slug))
102
99
  end
103
100
  end
104
101
 
@@ -112,14 +109,14 @@ module Binda
112
109
  # # returns all field settings
113
110
  #
114
111
  # B.get_field_settings('subtitle')
115
- # # returns an ActiveRelation (a sort of Array) containing the 'subtitle' field setting
112
+ # # returns an ActiveRecord::Relation (a sort of Array) containing the 'subtitle' field setting
116
113
  #
117
114
  # @param slug [string] The slug of a specific field setting
118
115
  # @param slug [array] The slugs of the selected field settings
119
116
  #
120
- # @return [ActiveRelation Object]
117
+ # @return [ActiveRecord::Relation]
121
118
  #
122
- def get_field_settings slug = nil
119
+ def get_field_settings(slug = nil)
123
120
  if slug.nil?
124
121
  FieldSetting.all
125
122
  else
@@ -134,14 +131,14 @@ module Binda
134
131
  #
135
132
  # @return [Array]
136
133
  #
137
- def get_relation_owners field_slug
134
+ def get_relation_owners(field_slug)
138
135
  owner_class = Structure.includes(field_groups: :field_settings)
139
- .where(binda_field_settings: {id: FieldSetting.where(slug: field_slug)})
136
+ .where(binda_field_settings: { id: FieldSetting.where(slug: field_slug) })
140
137
  .first
141
138
  obj = "Binda::#{owner_class.instance_type.classify}".constantize
142
139
  .distinct
143
140
  .includes(relations: :dependent_components)
144
- .where(binda_relations: {field_setting_id: FieldSetting.where(slug: field_slug)})
141
+ .where(binda_relations: { field_setting_id: FieldSetting.where(slug: field_slug) })
145
142
  raise ArgumentError, "There isn't any instance with a relation associated to the current slug (#{field_slug}).", caller if obj.nil?
146
143
  return obj
147
144
  end
@@ -162,25 +159,37 @@ module Binda
162
159
  #
163
160
  # @return [Array]
164
161
  #
165
- def get_relation_dependents field_slug, instance_type = nil
162
+ def get_relation_dependents(field_slug, instance_type = nil)
166
163
  raise ArgumentError, "There isn't any instance named: #{instance_type}. Make sure is either 'component' or 'board'", caller if !instance_type.nil? && ['board','component'].include?(instance_type)
167
164
 
168
- dependents = []
169
- if instance_type != 'board'
170
- dependent_components = Component.distinct
171
- .includes(:owner_components)
172
- .where(binda_relations: {field_setting_id: FieldSetting.where(slug: field_slug)})
173
- dependents = [ *dependents, *dependent_components ]
174
- elsif instance_type != 'component'
175
- dependent_boards = Board.distinct
176
- .includes(:owner_components)
177
- .where(binda_relations: {field_setting_id: FieldSetting.where(slug: field_slug)})
178
- dependents = [ *dependents, *dependent_boards ]
179
- end
165
+ dependents = get_dependents(instance_type, field_slug)
180
166
 
181
167
  raise ArgumentError, "There isn't any instance with a relation associated to the current slug (#{field_slug}).", caller unless dependents.any?
182
168
  return dependents
183
169
  end
170
+
171
+ private
172
+
173
+ # Get dependents based on slug and instance type
174
+ #
175
+ # @param instance_type [string] The instance type of the record (either board or component)
176
+ # @param field_slug [string] The record slug
177
+ # @return [array] Array of ActiveRecord dependents
178
+ def get_dependents(instance_type, field_slug)
179
+ dependents = []
180
+ if instance_type != 'board'
181
+ dependent_components = Component.distinct
182
+ .includes(:owner_components)
183
+ .where(binda_relations: { field_setting_id: FieldSetting.where(slug: field_slug) })
184
+ dependents = [ *dependents, *dependent_components ]
185
+ elsif instance_type != 'component'
186
+ dependent_boards = Board.distinct
187
+ .includes(:owner_components)
188
+ .where(binda_relations: { field_setting_id: FieldSetting.where(slug: field_slug) })
189
+ dependents = [ *dependents, *dependent_boards ]
190
+ end
191
+ return dependents
192
+ end
184
193
  end
185
194
  end
186
195
  end
@@ -0,0 +1,6 @@
1
+ Binda::Deprecation
2
+ .new
3
+ .deprecate_methods(
4
+ Binda::FieldableAssociations,
5
+ get_selection_choice: :get_selection_choices
6
+ )
@@ -0,0 +1,366 @@
1
+ module Binda
2
+ module FieldableAssociationHelpers
3
+
4
+ extend ActiveSupport::Concern
5
+
6
+ # Get the object related to that field setting
7
+ # If the object doesn't exists yet it will return nil
8
+ #
9
+ # @param field_slug [string] The slug of the field setting
10
+ # @return [string] Returns the content of the text
11
+ # @return [error] Raise an error if no record is found
12
+ def get_text(field_slug)
13
+ obj = self.texts.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type != 'Binda::String' }
14
+ unless obj.nil?
15
+ obj.content
16
+ else
17
+ check_text_error field_slug
18
+ end
19
+ end
20
+
21
+ # Check why get_text doesn't return a value
22
+ # This method isn't supposed to be used by anything other than get_text method
23
+ def check_text_error(field_slug)
24
+ you_mean_string = !self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type = 'Binda::String' }.nil?
25
+ if you_mean_string
26
+ raise ArgumentError, "This slug (#{field_slug}) is associated to a string not a text. Use get_string() instead on instance (#{self.class.name} ##{self.id}).", caller
27
+ else
28
+ raise ArgumentError, "There isn't any text associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller
29
+ end
30
+ end
31
+
32
+ # Get the object related to that field setting
33
+ #
34
+ # @param field_slug [string] The slug of the field setting
35
+ # @return [boolean]
36
+ def has_text(field_slug)
37
+ obj = self.texts.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type != 'Binda::String' }
38
+ raise ArgumentError, "There isn't any text associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
39
+ if obj.present?
40
+ return !obj.content.nil?
41
+ else
42
+ return false
43
+ end
44
+ end
45
+
46
+ # Get the object related to that field setting
47
+ # If the object doesn't exists yet it will return nil
48
+ #
49
+ # @param field_slug [string] The slug of the field setting
50
+ # @return [string] Returns the content of the string
51
+ # @return [error] Raise an error if no record is found
52
+ def get_string(field_slug)
53
+ obj = self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type == 'Binda::String' }
54
+ unless obj.nil?
55
+ obj.content
56
+ else
57
+ check_string_error field_slug
58
+ end
59
+ end
60
+
61
+ # Check why get_string doesn't return a value
62
+ # This method isn't supposed to be used by anything other than get_string method
63
+ def check_string_error(field_slug)
64
+ you_mean_text = !self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type = 'Binda::Text' }.nil?
65
+ if you_mean_text
66
+ raise ArgumentError, "This slug (#{field_slug}) is associated to a text not a string. Use get_text() instead on instance (#{self.class.name} ##{self.id}).", caller
67
+ else
68
+ raise ArgumentError, "There isn't any string associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller
69
+ end
70
+ end
71
+
72
+ # Get the object related to that field setting
73
+ #
74
+ # @param field_slug [string] The slug of the field setting
75
+ # @return [boolean]
76
+ def has_string(field_slug)
77
+ obj = self.strings.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) && t.type == 'Binda::String' }
78
+ raise ArgumentError, "There isn't any string associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
79
+ if obj.present?
80
+ return !obj.content.nil?
81
+ else
82
+ return false
83
+ end
84
+ end
85
+
86
+ # Check if the field has an attached image
87
+ #
88
+ # @param field_slug [string] The slug of the field setting
89
+ # @return [boolean]
90
+ def has_image(field_slug)
91
+ obj = self.images.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
92
+ # Alternative query
93
+ # obj = Image.where(field_setting_id: FieldSetting.get_id( field_slug ), fieldable_id: self.id, fieldable_type: self.class.to_s ).first
94
+ raise ArgumentError, "There isn't any image associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
95
+ return obj.image.present?
96
+ end
97
+
98
+ # Get the image url based on the size provided,
99
+ # default is Carrierwave default (usually the real size)
100
+ #
101
+ # @param field_slug [string] The slug of the field setting
102
+ # @param size [string] The size. It can be 'thumb' 200x200 cropped,
103
+ # 'medium' 700x700 max size, 'large' 1400x1400 max size, or blank
104
+ # @return [string] The url of the image
105
+ def get_image_url(field_slug, size = '')
106
+ get_image_info( field_slug, size, 'url' )
107
+ end
108
+
109
+ # Get the image path based on the size provided,
110
+ # default is Carrierwave default (usually the real size)
111
+ #
112
+ # @param field_slug [string] The slug of the field setting
113
+ # @param size [string] The size. It can be 'thumb' 200x200 cropped,
114
+ # 'medium' 700x700 max size, 'large' 1400x1400 max size, or blank
115
+ # @return [string] The url of the image
116
+ def get_image_path(field_slug, size = '')
117
+ get_image_info( field_slug, size, 'path' )
118
+ end
119
+
120
+ # Get the object related to that field setting
121
+ #
122
+ # @param field_slug [string] The slug of the field setting
123
+ # @param size [string] The size. It can be 'thumb' 200x200 cropped,
124
+ # 'medium' 700x700 max size, 'large' 1400x1400 max size, or blank
125
+ # @param info [string] String of the info to be retrieved
126
+ # @return [string] The info requested if present
127
+ # @return [boolean] Returns false if no info is found or if image isn't found
128
+ def get_image_info(field_slug, size, info)
129
+ obj = self.images.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
130
+ # Alternative query
131
+ # obj = Image.where(field_setting_id: FieldSetting.get_id( field_slug ), fieldable_id: self.id, fieldable_type: self.class.to_s ).first
132
+ raise ArgumentError, "There isn't any image associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
133
+ if obj.image.present? && obj.image.respond_to?(size) && %w[thumb medium large].include?(size)
134
+ obj.image.send(size).send(info)
135
+ elsif obj.image.present?
136
+ obj.image.send(info)
137
+ else
138
+ raise "Looks like the image you are looking for isn't present. See field setting with slug=\"#{field_slug}\" on component with id=\"self.id\""
139
+ end
140
+ end
141
+
142
+ def get_image_dimension(field_slug)
143
+ obj = self.images.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
144
+
145
+ raise ArgumentError, "There isn't any image associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
146
+ if obj.image.present? && obj.image.respond_to?(size) && %w[thumb medium large].include?(size)
147
+ obj.image.send(size).send(info)
148
+ elsif obj.image.present?
149
+ obj.image.send(info)
150
+ else
151
+ raise "Looks like the image you are looking for isn't present. See field setting with slug=\"#{field_slug}\" on component with id=\"self.id\""
152
+ end
153
+ end
154
+
155
+ # Check if the field has an attached video
156
+ #
157
+ # @param field_slug [string] The slug of the field setting
158
+ # @return [boolean]
159
+ def has_video(field_slug)
160
+ obj = self.videos.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
161
+ # Alternative query
162
+ # obj = Image.where(field_setting_id: FieldSetting.get_id( field_slug ), fieldable_id: self.id, fieldable_type: self.class.to_s ).first
163
+ raise ArgumentError, "There isn't any video associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
164
+ return obj.video.present?
165
+ end
166
+
167
+ # Get the video url based on the size provided,
168
+ # default is Carrierwave default (usually the real size)
169
+ #
170
+ # @param field_slug [string] The slug of the field setting
171
+ # @param size [string] The size. It can be 'thumb' 200x200 cropped,
172
+ # 'medium' 700x700 max size, 'large' 1400x1400 max size, or blank
173
+ # @return [string] The url of the video
174
+ def get_video_url(field_slug)
175
+ get_video_info( field_slug, 'url' )
176
+ end
177
+
178
+ # Get the video path based on the size provided,
179
+ # default is Carrierwave default (usually the real size)
180
+ #
181
+ # @param field_slug [string] The slug of the field setting
182
+ # @param size [string] The size. It can be 'thumb' 200x200 cropped,
183
+ # 'medium' 700x700 max size, 'large' 1400x1400 max size, or blank
184
+ # @return [string] The url of the video
185
+ def get_video_path(field_slug)
186
+ get_video_info( field_slug, 'path' )
187
+ end
188
+
189
+ # Get the object related to that field setting
190
+ #
191
+ # @param field_slug [string] The slug of the field setting
192
+ # @param info [string] String of the info to be retrieved
193
+ # @return [string] The info requested if present
194
+ # @return [boolean] Returns false if no info is found or if image isn't found
195
+ def get_video_info(field_slug, info)
196
+ obj = self.videos.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
197
+ # Alternative query
198
+ # obj = video.where(field_setting_id: FieldSetting.get_id( field_slug ), fieldable_id: self.id, fieldable_type: self.class.to_s ).first
199
+ raise ArgumentError, "There isn't any video associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
200
+ if obj.video.present?
201
+ obj.video.send(info)
202
+ end
203
+ end
204
+
205
+ # Check if the field has an attached date
206
+ #
207
+ # @param field_slug [string] The slug of the field setting
208
+ # @return [datetime] The date
209
+ # @return [boolean] Reutrn false if nothing is found
210
+ def has_date(field_slug)
211
+ obj = self.dates.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
212
+ raise ArgumentError, "There isn't any date associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
213
+ if obj.present?
214
+ return !obj.date.nil?
215
+ else
216
+ return false
217
+ end
218
+ end
219
+
220
+ # Get the object related to that field setting
221
+ #
222
+ # @param field_slug [string] The slug of the field setting
223
+ # @return [boolean]
224
+ def get_date(field_slug)
225
+ obj = self.dates.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
226
+ raise ArgumentError, "There isn't any date associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
227
+ obj.date
228
+ end
229
+
230
+ # Check if exists any repeater with that slug
231
+ #
232
+ # @param field_slug [string] The slug of the field setting
233
+ # @return [boolean]
234
+ def has_repeater(field_slug)
235
+ obj = self.repeaters.find_all{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
236
+ raise ArgumentError, "There isn't any repeater associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
237
+ return obj.present?
238
+ end
239
+
240
+ # Get the all repeater instances sorted by position
241
+ #
242
+ # @param field_slug [string] The slug of the field setting
243
+ # @return [array] An array of repeater items which have all sorts of fields attached
244
+ def get_repeater(field_slug)
245
+ obj = self.repeaters.find_all{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
246
+ raise ArgumentError, "There isn't any repeater associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
247
+ obj.sort_by(&:position)
248
+ end
249
+
250
+ # Get the radio choice
251
+ #
252
+ # If by mistake the Radio instance has many choices associated,
253
+ # only the first one will be retrieved.
254
+ #
255
+ # @param field_slug [string] The slug of the field setting
256
+ # @return [hash] A hash of containing the label and value of the selected choice. `{ label: 'the label', value: 'the value'}`
257
+ def get_radio_choice(field_slug)
258
+ field_setting = FieldSetting.find_by(slug:field_slug)
259
+ obj = self.radios.find{ |t| t.field_setting_id == field_setting.id }
260
+ raise ArgumentError, "There isn't any radio associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
261
+ raise "There isn't any choice available for the current radio (#{field_slug}) on instance (#{self.class.name} ##{self.id})." unless obj.choices.any?
262
+ return { label: obj.choices.first.label, value: obj.choices.first.value }
263
+ end
264
+
265
+ # Get the select choices
266
+ #
267
+ # @param field_slug [string] The slug of the field setting
268
+ # @return [hash] A hash of containing the label and value of the selected choice. `{ label: 'the label', 'value': 'the value'}`
269
+ def get_selection_choice(field_slug)
270
+ field_setting = FieldSetting.find_by(slug:field_slug)
271
+ obj = self.selections.find{ |t| t.field_setting_id == field_setting.id }
272
+ raise ArgumentError, "There isn't any selection associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
273
+ raise "There isn't any choice available for the current selection (#{field_slug}) on instance (#{self.class.name} ##{self.id})." unless field_setting.choices.any?
274
+ return { label: obj.choices.first.label, value: obj.choices.first.value }
275
+ end
276
+
277
+ # Get the select choices
278
+ #
279
+ # @param field_slug [string] The slug of the field setting
280
+ # @return [array] An array of hashes of containing label and value of the selected choices. `{ label: 'the label', 'value': 'the value'}`
281
+ def get_selection_choices(field_slug)
282
+ field_setting = FieldSetting.find_by(slug:field_slug)
283
+ obj = self.selections.find{ |t| t.field_setting_id == field_setting.id }
284
+ raise ArgumentError, "There isn't any selection associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
285
+ raise "There isn't any choice available for the current selection (#{field_slug}) on instance (#{self.class.name} ##{self.id})." unless field_setting.choices.any?
286
+ return obj.choices.map{|choice| { label: choice.label, value: choice.value }}
287
+ end
288
+
289
+ # Get the checkbox choice
290
+ #
291
+ # @param field_slug [string] The slug of the field setting
292
+ # @return [array] An array of labels and values of the selected choices. `[{ label: '1st label', value: '1st-value'}, { label: '2nd label', value: '2nd-value'}]`
293
+ def get_checkbox_choices(field_slug)
294
+ field_setting = FieldSetting.find_by(slug:field_slug)
295
+ obj = self.checkboxes.find{ |t| t.field_setting_id == field_setting.id }
296
+ raise ArgumentError, "There isn't any checkbox associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
297
+ raise "There isn't any choice available for the current checkbox (#{field_slug}) on instance (#{self.class.name} ##{self.id})." unless field_setting.choices.any?
298
+ obj_array = []
299
+ obj.choices.order('label').each do |o|
300
+ obj_array << { label: o.label, value: o.value }
301
+ end
302
+ return obj_array
303
+ end
304
+
305
+ # Check if has related components
306
+ #
307
+ # @param field_slug [string] The slug of the field setting
308
+ # @return [boolean]
309
+ def has_related_components(field_slug)
310
+ obj = self.relations.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
311
+ raise ArgumentError, "There isn't any related field associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
312
+ return obj.dependent_relations.any?
313
+ end
314
+
315
+ # Alias for has_related_components
316
+ def has_dependent_components(field_slug)
317
+ has_related_components(field_slug)
318
+ end
319
+
320
+ # Get related components
321
+ #
322
+ # @param field_slug [string] The slug of the field setting
323
+ # @return [array] An array of components
324
+ def get_related_components(field_slug)
325
+ obj = self.relations.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
326
+ raise ArgumentError, "There isn't any related field associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
327
+ return obj.dependent_relations.map{|relation| relation.dependent}
328
+ end
329
+
330
+ # Alias for get_related_components
331
+ def get_dependent_components(field_slug)
332
+ get_related_components(field_slug)
333
+ end
334
+
335
+ # Get all components which owns a relation where the current instance is a dependent
336
+ #
337
+ # @param field_slug [string] The slug of the field setting of the relation
338
+ # @return [array] An array of components and/or boards
339
+ def get_owner_components(field_slug)
340
+ # obj = self.owner_relations.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
341
+ obj = Relation.where(field_setting_id: B.get_field_settings(field_slug)).includes(dependent_relations: :dependent).where(binda_relation_links: {dependent_type: self.class.name})
342
+ raise ArgumentError, "There isn't any relation associated to the current slug (#{field_slug}) where the current instance (#{self.class.name} ##{self.id}) is a dependent.", caller if obj.nil?
343
+ return obj
344
+ end
345
+
346
+ # Check if has related boards
347
+ #
348
+ # @param field_slug [string] The slug of the field setting
349
+ # @return [boolean]
350
+ def has_related_boards(field_slug)
351
+ obj = self.relations.find{ |t| t.field_setting_id == FieldSetting.get_id( field_slug ) }
352
+ raise ArgumentError, "There isn't any related field associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
353
+ return obj.dependent_relations.any?
354
+ end
355
+
356
+ # Get related boards
357
+ #
358
+ # @param field_slug [string] The slug of the field setting
359
+ # @return [array] An array of boards
360
+ def get_related_boards(field_slug)
361
+ obj = self.relations.find{ |t| t.field_setting_idid == FieldSetting.get_id( field_slug ) }
362
+ raise ArgumentError, "There isn't any related field associated to the current slug (#{field_slug}) on instance (#{self.class.name} ##{self.id}).", caller if obj.nil?
363
+ return obj.dependent_relations.map{|relation| relation.dependent}
364
+ end
365
+ end
366
+ end