web47core 3.2.36 → 3.2.50
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/app/helpers/core_form_checkbox_helper.rb +43 -0
- data/app/helpers/core_form_helper.rb +177 -120
- data/app/helpers/core_form_input_helper.rb +74 -0
- data/app/helpers/core_form_select_helper.rb +65 -0
- data/app/helpers/core_form_textarea_helper.rb +22 -0
- data/app/helpers/core_link_helper.rb +0 -8
- data/app/helpers/core_table_helper.rb +23 -0
- data/app/helpers/model_modal_helper.rb +80 -47
- data/app/helpers/svg_icon_helper.rb +10 -6
- data/config/locales/en.yml +1 -0
- data/lib/app/models/concerns/standard_model.rb +8 -7
- data/lib/web47core/version.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c3675d2ab5fbd549deab9374e349736b27f3f648bd12d3a29566c5b0af3bbea
|
4
|
+
data.tar.gz: fd2209c37ae9f88094037c1b28af3e5d4ee4420e98aff389ac86f724b2a4a4e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c7a42d5c97ee0b629eee606061c871e75c67e2499ec18158fc8a52c5e2bef28d73a29b32dd08fae4a982206e7b0409c089401defcdf90a2c16dad3309cd874ba
|
7
|
+
data.tar.gz: 4bf04e44e0cb319e79c92aaaa65abd328a00f12c6e9667906991d2139e80416cfcf7ba12acf335aeff7f0b5028a04cf8f43da29c2b9219ae4e7307cbb620bd4c
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module CoreFormCheckboxHelper
|
2
|
+
# @abstract Render a text field
|
3
|
+
# @param [Mongoid::Document] model - The model to render the field for
|
4
|
+
# @param [Symbol] field - The field to render
|
5
|
+
# @param [Hash] options - Options to pass to the field
|
6
|
+
def form_checkbox(model, field, options = {})
|
7
|
+
classes = options[:classes] || []
|
8
|
+
value = model.send(field)
|
9
|
+
options[:disabled] ||= false
|
10
|
+
properties = {
|
11
|
+
class: 'form-check-input',
|
12
|
+
id: form_field_id(model, field, options),
|
13
|
+
name: form_field_name(model, field, options),
|
14
|
+
type: :checkbox,
|
15
|
+
disabled: options[:disabled]
|
16
|
+
}
|
17
|
+
properties[:checked] = true if model.send(field)
|
18
|
+
checkbox_tag = tag(:input, properties)
|
19
|
+
content_tag(:div, class: (%w[mb-3 align-items-center d-flex] + classes).join(' ')) do
|
20
|
+
concat(content_tag(:label, class: 'form-check form-switch align-middle') do
|
21
|
+
concat(checkbox_tag)
|
22
|
+
concat(form_checkbox_label_tag(model, field, value, input_classes: classes))
|
23
|
+
end)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def form_checkbox_label_tag(model, field, value, options = {})
|
28
|
+
# dont do a label if we are in default browser mode
|
29
|
+
return if options[:input_classes].present? && options[:input_classes].include?('browser-default')
|
30
|
+
|
31
|
+
# or if we have a prompt with now value
|
32
|
+
place_holder = form_place_holder_text(model, field)
|
33
|
+
return if place_holder.blank? && value.blank? && options[:prompt].present?
|
34
|
+
|
35
|
+
error = model.errors[field]
|
36
|
+
label = input_label(model, field)
|
37
|
+
classes = value.nil? && place_holder.blank? ? '' : 'active'
|
38
|
+
classes += error.present? ? ' invalid red-text' : ' valid'
|
39
|
+
options[:class] = classes
|
40
|
+
options['data-error'] = error.join(', ') if error.present?
|
41
|
+
content_tag(:span, options) { label}
|
42
|
+
end
|
43
|
+
end
|
@@ -4,11 +4,11 @@
|
|
4
4
|
# helpers for creating forms
|
5
5
|
#
|
6
6
|
module CoreFormHelper
|
7
|
-
def materialize_form_for(options = {}, &block)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
end
|
7
|
+
# def materialize_form_for(options = {}, &block)
|
8
|
+
# options[:form_authenticity_token] = form_authenticity_token
|
9
|
+
# form = Materialize::Form.new(options)
|
10
|
+
# form.render_form(&block)
|
11
|
+
# end
|
12
12
|
|
13
13
|
#
|
14
14
|
# Text area
|
@@ -37,18 +37,18 @@ module CoreFormHelper
|
|
37
37
|
#
|
38
38
|
# Text field
|
39
39
|
#
|
40
|
-
def form_text_field(model, field, options = {})
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
end
|
40
|
+
# def form_text_field(model, field, options = {})
|
41
|
+
# classes = options[:classes] || %w[s12 m6 l4 xl3]
|
42
|
+
# value = model.send(field)
|
43
|
+
# options[:type] ||= :text
|
44
|
+
# options[:value] = value
|
45
|
+
# options[:disabled] ||= false
|
46
|
+
# tag_options = text_field_options(model, field, options)
|
47
|
+
# content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
48
|
+
# concat(tag(:input, tag_options))
|
49
|
+
# concat(form_label_tag(model, field, value, options))
|
50
|
+
# end
|
51
|
+
# end
|
52
52
|
|
53
53
|
def form_date_field(model, field, options = {})
|
54
54
|
classes = options[:classes] || %w[s12 m6 l4 xl3]
|
@@ -84,17 +84,17 @@ module CoreFormHelper
|
|
84
84
|
#
|
85
85
|
# Password field
|
86
86
|
#
|
87
|
-
def form_password(model, field, options = {})
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
87
|
+
# def form_password(model, field, options = {})
|
88
|
+
# classes = options[:classes] || %w[s12 m6 l4 xl3]
|
89
|
+
# value = model.send(field)
|
90
|
+
# options[:type] = :password
|
91
|
+
# options[:place_holder] ||= mask_value(value)
|
92
|
+
# tag_options = text_field_options(model, field, options)
|
93
|
+
# content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
94
|
+
# concat(tag(:input, tag_options))
|
95
|
+
# concat(form_label_tag(model, field, value, options))
|
96
|
+
# end
|
97
|
+
# end
|
98
98
|
|
99
99
|
#
|
100
100
|
# Select field
|
@@ -170,47 +170,47 @@ module CoreFormHelper
|
|
170
170
|
#
|
171
171
|
# Checkbox field
|
172
172
|
#
|
173
|
-
def form_checkbox(model, field, classes = %w[s12 m6 l4 xl3], options = {})
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
end
|
173
|
+
# def form_checkbox(model, field, classes = %w[s12 m6 l4 xl3], options = {})
|
174
|
+
# value = model.send(field)
|
175
|
+
# options[:disabled] ||= false
|
176
|
+
# properties = {
|
177
|
+
# class: 'validate',
|
178
|
+
# id: form_field_id(model, field, options),
|
179
|
+
# name: form_field_name(model, field, options),
|
180
|
+
# type: :checkbox,
|
181
|
+
# disabled: options[:disabled]
|
182
|
+
# }
|
183
|
+
# properties[:checked] = true if model.send(field)
|
184
|
+
# checkbox_tag = tag(:input, properties)
|
185
|
+
# content_tag(:div, class: (%w[input-field col] + classes).join(' ')) do
|
186
|
+
# concat(content_tag(:label) do
|
187
|
+
# concat(checkbox_tag)
|
188
|
+
# concat(form_checkbox_label_tag(model, field, value, input_classes: classes))
|
189
|
+
# end)
|
190
|
+
# end
|
191
|
+
# end
|
192
192
|
|
193
193
|
#
|
194
194
|
# get the label for checkbox
|
195
195
|
#
|
196
|
-
def form_checkbox_label_tag(model, field, value, options = {})
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
end
|
196
|
+
# def form_checkbox_label_tag(model, field, value, options = {})
|
197
|
+
# # dont do a label if we are in default browser mode
|
198
|
+
# return if options[:input_classes].present? && options[:input_classes].include?('browser-default')
|
199
|
+
#
|
200
|
+
# # or if we have a prompt with now value
|
201
|
+
# place_holder = field_place_holder(model, field)
|
202
|
+
# return if place_holder.blank? && value.blank? && options[:prompt].present?
|
203
|
+
#
|
204
|
+
# error = model.errors[field]
|
205
|
+
# key = "ui_form.#{model.class.to_s.underscore}.labels.#{field}"
|
206
|
+
# classes = value.nil? && place_holder.blank? ? '' : 'active'
|
207
|
+
# classes += error.present? ? ' invalid red-text' : ' valid'
|
208
|
+
# options[:class] = classes
|
209
|
+
# options['data-error'] = error.join(', ') if error.present?
|
210
|
+
# content_tag(:span, options) do
|
211
|
+
# concat(I18n.exists?(key) ? I18n.t(key) : field.to_s.humanize)
|
212
|
+
# end
|
213
|
+
# end
|
214
214
|
|
215
215
|
#
|
216
216
|
# File field
|
@@ -230,24 +230,28 @@ module CoreFormHelper
|
|
230
230
|
# get the label for field
|
231
231
|
#
|
232
232
|
def form_label_tag(model, field, value, options = {})
|
233
|
-
#
|
233
|
+
# don't do a label if we are in default browser mode
|
234
234
|
return if options[:no_label]
|
235
235
|
return if options[:input_classes].present? && options[:input_classes].include?('browser-default')
|
236
236
|
|
237
|
+
help_text = form_helper_text(model, field)
|
238
|
+
|
237
239
|
# or if we have a prompt with now value
|
238
|
-
place_holder = options[:place_holder] ||
|
240
|
+
place_holder = options[:place_holder] || form_place_holder_text(model, field)
|
239
241
|
return if place_holder.blank? && value.blank? && options[:prompt].present?
|
240
242
|
|
241
243
|
error = model.errors[field]
|
242
|
-
|
243
|
-
classes
|
244
|
-
|
245
|
-
options[:class] = classes
|
244
|
+
classes = %w[form-label mb-2]
|
245
|
+
classes << 'text-red' if error.present?
|
246
|
+
options[:class] = classes.compact.uniq.join(' ')
|
246
247
|
options[:for] = form_field_id(model, field, options)
|
247
|
-
options['data-error'] = error.join(', ') if error.present?
|
248
|
-
|
249
|
-
|
250
|
-
concat(
|
248
|
+
# options['data-error'] = error.join(', ') if error.present?
|
249
|
+
options[:required] = form_required_field?(model, field) ? 'required' : nil
|
250
|
+
tag.label(**options) do
|
251
|
+
concat(input_label(model, field, field.to_s.humanize))
|
252
|
+
concat(content_tag(:span, class: 'form-help ms-2', data: { bs_toggle: :popover, bs_content: help_text }) { '?' }) if help_text.present?
|
253
|
+
# @todo CMS add handling specific errors later
|
254
|
+
# concat(" #{error.join(', ')}") if error.present?
|
251
255
|
end
|
252
256
|
end
|
253
257
|
|
@@ -266,35 +270,37 @@ module CoreFormHelper
|
|
266
270
|
#
|
267
271
|
# Add the placeholder option if found in the translations
|
268
272
|
#
|
269
|
-
def text_field_options(model, field, options)
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
end
|
273
|
+
# def text_field_options(model, field, options)
|
274
|
+
# hint_key = "ui_form.#{model.class.to_s.underscore}.hints.#{field}"
|
275
|
+
# if I18n.exists?(hint_key)
|
276
|
+
# classes = %w[validate tooltipped]
|
277
|
+
# options[:data] = { tooltip: I18n.t(hint_key), position: :top }
|
278
|
+
# else
|
279
|
+
# classes = %w[validate]
|
280
|
+
# end
|
281
|
+
# classes += options[:input_classes] if options[:input_classes].present?
|
282
|
+
# options[:name] = form_field_name(model, field, options)
|
283
|
+
# options[:id] = form_field_id(model, field, options)
|
284
|
+
# place_holder = options[:place_holder] || field_place_holder(model, field)
|
285
|
+
# if place_holder.present?
|
286
|
+
# classes << 'active'
|
287
|
+
# options[:placeholder] = place_holder
|
288
|
+
# end
|
289
|
+
# classes << 'active' if options[:value].present?
|
290
|
+
# options[:class] = classes.uniq
|
291
|
+
# options
|
292
|
+
# end
|
289
293
|
|
290
|
-
def field_place_holder(model, field)
|
291
|
-
|
292
|
-
|
293
|
-
end
|
294
|
+
# def field_place_holder(model, field)
|
295
|
+
# place_holder_key = "ui_form.#{model.class.to_s.underscore}.placeholders.#{field}"
|
296
|
+
# I18n.exists?(place_holder_key) ? I18n.t(place_holder_key) : nil
|
297
|
+
# end
|
294
298
|
|
295
|
-
#
|
296
|
-
#
|
297
|
-
#
|
299
|
+
# @abstract Return a consistent form field name
|
300
|
+
# @param [Mongoid::Document] model
|
301
|
+
# @param [Symbol] field
|
302
|
+
# @param [Hash] options
|
303
|
+
# @return [HTML]
|
298
304
|
def form_field_name(model, field, options = {})
|
299
305
|
return options[:form_name] if options[:form_name].present?
|
300
306
|
|
@@ -316,28 +322,26 @@ module CoreFormHelper
|
|
316
322
|
end
|
317
323
|
end
|
318
324
|
|
319
|
-
#
|
320
|
-
#
|
321
|
-
#
|
325
|
+
# @abstract Return a consistent form field id
|
326
|
+
# @param [Mongoid::Document] model
|
327
|
+
# @param [Symbol] field
|
328
|
+
# @param [Hash] options
|
329
|
+
# @return [HTML]
|
322
330
|
def form_field_id(model, field, options = {})
|
323
331
|
return options[:form_id] if options[:form_id].present?
|
324
332
|
|
325
|
-
# TODO: Need to handle the other side of the 1:M use case where
|
326
|
-
# the field name needs to end in _ids, not _id.
|
327
333
|
field = "#{field}_id" if model.class.reflect_on_association(field).present?
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
"#{options[:form_id_prefix]}#{model.class.to_s.underscore}[#{field}]"
|
340
|
-
end
|
334
|
+
[options[:form_id_prefix], options[:base_name], options[:array_name] || model.class.to_s.underscore, options[:index], field].compact.join('_')
|
335
|
+
end
|
336
|
+
|
337
|
+
# @abstract Determine if the field is required or not
|
338
|
+
# @param [Mongoid::Document] model
|
339
|
+
# @param [Symbol] field
|
340
|
+
# @return [Boolean]
|
341
|
+
def form_required_field?(model, field)
|
342
|
+
model.class.validators_on(field).any? { |v| v.is_a?(Mongoid::Validatable::PresenceValidator) }
|
343
|
+
rescue StandardError
|
344
|
+
false
|
341
345
|
end
|
342
346
|
|
343
347
|
def form_radio_button(model, field, options = {})
|
@@ -348,4 +352,57 @@ module CoreFormHelper
|
|
348
352
|
concat(form_label_tag(model, field, value))
|
349
353
|
end
|
350
354
|
end
|
355
|
+
|
356
|
+
# @abstract Get the placeholder for this input element
|
357
|
+
# @param [Mongoid::Document] model
|
358
|
+
# @param [Symbol] field
|
359
|
+
# @param [String, nil] default
|
360
|
+
# @return [String, nil]
|
361
|
+
def form_place_holder_text(model, field, default = nil)
|
362
|
+
form_localized_text(model, field, :placeholders, default)
|
363
|
+
end
|
364
|
+
|
365
|
+
# @abstract Get the helper text for this input element
|
366
|
+
# @param [Mongoid::Document] model
|
367
|
+
# @param [Symbol] field
|
368
|
+
# @param [String, nil] default
|
369
|
+
# @return [String, nil]
|
370
|
+
def form_helper_text(model, field, default = nil)
|
371
|
+
form_localized_text(model, field, :helpers, default)
|
372
|
+
end
|
373
|
+
|
374
|
+
# @abstract Get the hint text for this input element
|
375
|
+
# @param [Mongoid::Document] model
|
376
|
+
# @param [Symbol] field
|
377
|
+
# @param [String, nil] default
|
378
|
+
# @return [String,nil]
|
379
|
+
def form_hint_text(model, field, default = nil)
|
380
|
+
form_localized_text(model, field, :hints, default)
|
381
|
+
end
|
382
|
+
|
383
|
+
# @abstract Get the label for this input element
|
384
|
+
# @param [Mongoid::Document] model
|
385
|
+
# @param [Symbol] field
|
386
|
+
# @param [String, nil] default
|
387
|
+
# @return [String,nil]
|
388
|
+
def input_label(model, field, default = model.class.human_attribute_name(field))
|
389
|
+
form_localized_text(model, field, :labels, default)
|
390
|
+
end
|
391
|
+
|
392
|
+
def required_field?(model, field)
|
393
|
+
form_required_field?(model, field)
|
394
|
+
end
|
395
|
+
|
396
|
+
# @abstract Get the localized value for the given key
|
397
|
+
# @param [Mongoid::Document] model
|
398
|
+
# @param [Symbol] field
|
399
|
+
# @param [Symbol] type
|
400
|
+
# @param [String] default
|
401
|
+
# @return [String,nil]
|
402
|
+
def form_localized_text(model, field, type, default = nil)
|
403
|
+
key = ['ui_form', model.class.to_s.underscore, type, field].join('.')
|
404
|
+
I18n.exists?(key) ? I18n.t(key) : default
|
405
|
+
rescue StandardError
|
406
|
+
default
|
407
|
+
end
|
351
408
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module CoreFormInputHelper
|
2
|
+
|
3
|
+
# @abstract Render a email text field
|
4
|
+
# @param [Mongoid::Document] model - The model to render the field for
|
5
|
+
# @param [Symbol] field - The field to render
|
6
|
+
# @param [Hash] options - Options to pass to the field
|
7
|
+
def form_number_field(model, field, options = {})
|
8
|
+
options[:type] ||= :number
|
9
|
+
options[:step] ||= 1
|
10
|
+
options[:min] ||= 0
|
11
|
+
form_text_field(model, field, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @abstract Render a email text field
|
15
|
+
# @param [Mongoid::Document] model - The model to render the field for
|
16
|
+
# @param [Symbol] field - The field to render
|
17
|
+
# @param [Hash] options - Options to pass to the field
|
18
|
+
def form_email_field(model, field, options = {})
|
19
|
+
options[:type] ||= :email
|
20
|
+
form_text_field(model, field, options)
|
21
|
+
end
|
22
|
+
|
23
|
+
# @abstract Render a text field
|
24
|
+
# @param [Mongoid::Document] model - The model to render the field for
|
25
|
+
# @param [Symbol] field - The field to render
|
26
|
+
# @param [Hash] options - Options to pass to the field
|
27
|
+
def form_url_field(model, field, options = {})
|
28
|
+
options[:type] ||= :url
|
29
|
+
form_text_field(model, field, options)
|
30
|
+
end
|
31
|
+
|
32
|
+
# @abstract Render a text field
|
33
|
+
# @param [Mongoid::Document] model - The model to render the field for
|
34
|
+
# @param [Symbol] field - The field to render
|
35
|
+
# @param [Hash] options - Options to pass to the field
|
36
|
+
def form_password(model, field, options = {})
|
37
|
+
options[:type] = :password
|
38
|
+
form_text_field(model, field, options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# @abstract Render a text field
|
42
|
+
# @param [Mongoid::Document] model - The model to render the field for
|
43
|
+
# @param [Symbol] field - The field to render
|
44
|
+
# @param [Hash] options - Options to pass to the field
|
45
|
+
def form_text_field(model, field, options = {})
|
46
|
+
label_options = options.clone
|
47
|
+
classes = options[:classes] || []
|
48
|
+
classes << 'mb-3'
|
49
|
+
value = model.send(field)
|
50
|
+
options[:type] ||= :text
|
51
|
+
options[:value] = value
|
52
|
+
options[:disabled] ||= false
|
53
|
+
tag_options = text_field_options(model, field, options)
|
54
|
+
content_tag(:div, class: classes.join(' ')) do
|
55
|
+
concat(form_label_tag(model, field, value, label_options))
|
56
|
+
concat(tag(:input, tag_options))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @abstract Build the options for a text field, place holder, hint, etc.
|
61
|
+
# @param [Mongoid::Document] model - The model to render the field for
|
62
|
+
# @param [Symbol] field - The field to render
|
63
|
+
# @param [Hash] options - Options to pass to the field
|
64
|
+
def text_field_options(model, field, options = {})
|
65
|
+
classes = %w[form-control]
|
66
|
+
classes += options[:input_classes] if options[:input_classes].present?
|
67
|
+
options[:name] = form_field_name(model, field, options)
|
68
|
+
options[:id] = form_field_id(model, field, options)
|
69
|
+
place_holder = options[:place_holder] || form_place_holder_text(model, field)
|
70
|
+
options[:placeholder] = place_holder if place_holder.present?
|
71
|
+
options[:class] = classes.uniq
|
72
|
+
options
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module CoreFormSelectHelper
|
2
|
+
def form_select(model, field, options = {})
|
3
|
+
value = model.send(field)
|
4
|
+
raise 'Prompt needed' if value.blank? && options[:prompt].blank? && !options[:no_label]
|
5
|
+
|
6
|
+
label_options = options.clone
|
7
|
+
hint = input_hint(model, field)
|
8
|
+
if hint.present?
|
9
|
+
base_classes = %w[tooltipped]
|
10
|
+
data = { tooltip: I18n.t(hint_key), position: :top }
|
11
|
+
else
|
12
|
+
base_classes = []
|
13
|
+
data = {}
|
14
|
+
end
|
15
|
+
classes = (base_classes + (options[:classes] || %w[s12 m6 l4 xl3])).join(' ')
|
16
|
+
content_tag(:div, class: classes, data: data) do
|
17
|
+
concat(input_label_tag(model, field, value, options))
|
18
|
+
concat(form_input_select_tag(model, field, label_options))
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def form_select_tag(model, field, options = {})
|
23
|
+
select_content = {
|
24
|
+
id: form_field_id(model, field, options),
|
25
|
+
name: form_field_name(model, field, options),
|
26
|
+
class: [options[:input_classes], 'form-select'].compact.join(' '),
|
27
|
+
disabled: options[:disabled]
|
28
|
+
}
|
29
|
+
content_tag(:select, select_content) do
|
30
|
+
form_select_option_key_values(model.send(field), options).each do |value|
|
31
|
+
concat(content_tag(:option, value: value[:key], selected: value[:selected]) do
|
32
|
+
concat(value[:value])
|
33
|
+
end)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def form_select_option_key_values(value, options)
|
39
|
+
select_options = []
|
40
|
+
select_options << { key: '', value: options[:prompt], selected: false } if options[:prompt].present?
|
41
|
+
options[:options].each do |option_value|
|
42
|
+
option_value[:display_name] = option_value.display_name if option_value.respond_to?(:display_name)
|
43
|
+
option_value[:display_name] = option_value.user_display_name if option_value.respond_to?(:user_display_name)
|
44
|
+
select_options << case option_value
|
45
|
+
when String, Integer
|
46
|
+
{ key: option_value,
|
47
|
+
value: option_value,
|
48
|
+
selected: value.eql?(option_value) }
|
49
|
+
when Array
|
50
|
+
{ key: option_value.last,
|
51
|
+
value: option_value.first,
|
52
|
+
selected: value.to_s.eql?(option_value.last.to_s) }
|
53
|
+
when Hash
|
54
|
+
{ key: option_value[:key],
|
55
|
+
value: option_value[:value],
|
56
|
+
selected: value.eql?(option_value[:key]) }
|
57
|
+
else
|
58
|
+
{ key: option_value[:_id].to_s,
|
59
|
+
value: option_value[:display_name] || option_value[:name],
|
60
|
+
selected: value.eql?(option_value) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
select_options
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module CoreFormTextareaHelper
|
2
|
+
def form_textarea(model, field, options = {})
|
3
|
+
classes = options[:classes] || []
|
4
|
+
value = model.send(field)
|
5
|
+
# options[:value] = value
|
6
|
+
# options[:disabled] ||= false
|
7
|
+
# tag_options = {class: []} # text_field_options(model, field, options)
|
8
|
+
# tag_options[:class] += ['materialize-textarea']
|
9
|
+
content_tag(:div, class: (%w[mb-3] + classes).flatten.join(' ')) do
|
10
|
+
concat(input_label_tag(model, field, value, options))
|
11
|
+
concat(textarea_tag(model, field, value, options))
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def form_textarea_tag(model, field, value, options = {})
|
16
|
+
tag_options = text_input_options(model, field, options)
|
17
|
+
tag_options[:class] << 'form-control'
|
18
|
+
content_tag(:textarea, tag_options) do
|
19
|
+
concat(value)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -115,14 +115,6 @@ module CoreLinkHelper
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
|
-
def edit_modal_tag(obj, path, _options = {})
|
119
|
-
return unless can? :edit, obj
|
120
|
-
|
121
|
-
content_tag(:a, href: path, class: 'modal-action') do
|
122
|
-
concat(I18n.t('ui_form.actions.edit'))
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
118
|
#
|
127
119
|
# Restart a thingy
|
128
120
|
#
|
@@ -4,6 +4,16 @@
|
|
4
4
|
# Methods useful for building out tables
|
5
5
|
#
|
6
6
|
module CoreTableHelper
|
7
|
+
def card_table_header_actions_tag(clazz, path, classes: [], icon_name: :add, title: 'Add')
|
8
|
+
return unless can?(:create, clazz)
|
9
|
+
|
10
|
+
classes << 'btn'
|
11
|
+
content_tag(:a, class: classes.join(' '), href: path) do
|
12
|
+
concat(svg_icon(icon_name))
|
13
|
+
concat(content_tag(:span, title))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
7
17
|
#
|
8
18
|
# Format the table header
|
9
19
|
# @param name - Name of the header, either the text or a localized value
|
@@ -77,4 +87,17 @@ module CoreTableHelper
|
|
77
87
|
end)
|
78
88
|
end
|
79
89
|
end
|
90
|
+
|
91
|
+
# @abstract Return a table data cell with a boolean value
|
92
|
+
# @param value [Boolean] - The value to display
|
93
|
+
# @return [String] - The HTML for the cell
|
94
|
+
def table_data_boolean(value, show_false: true)
|
95
|
+
content_tag(:td, class: 'text-center', data: { order: value ? 0 : 1 }) do
|
96
|
+
if value
|
97
|
+
svg_icon(:check, color: :green)
|
98
|
+
else
|
99
|
+
svg_icon(:x, color: :red) if show_false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
80
103
|
end
|
@@ -69,15 +69,20 @@ module ModelModalHelper
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def model_modal_action(model, _options = {})
|
72
|
-
content_tag(:a,
|
72
|
+
content_tag(:a, href: '#', data: { bs_toggle: :modal, bs_target: "#modal-#{model.id}" }) do
|
73
73
|
concat(model.name)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
77
|
def model_modal(model, edit_path, options = {})
|
78
|
-
content_tag(:div, class: 'modal', id: "modal-#{model.id}") do
|
79
|
-
concat(
|
80
|
-
|
78
|
+
content_tag(:div, class: 'modal', id: "modal-#{model.id}", tabindex: -1) do
|
79
|
+
concat(model_modal_dialog(model, edit_path, options))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def model_modal_dialog(model, edit_path, options = {})
|
84
|
+
content_tag(:div, class: 'modal-dialog', role: :document) do
|
85
|
+
concat(model_modal_content(model, edit_path, options))
|
81
86
|
end
|
82
87
|
end
|
83
88
|
|
@@ -85,40 +90,60 @@ module ModelModalHelper
|
|
85
90
|
model_modal_content(model, options) + model_modal_footer(model, "#{request.url}/edit")
|
86
91
|
end
|
87
92
|
|
88
|
-
def model_modal_content(model, options = {})
|
93
|
+
def model_modal_content(model, edit_path, options = {})
|
89
94
|
content_tag(:div, class: 'modal-content') do
|
90
|
-
concat(
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
95
|
+
concat(model_modal_header(model, edit_path, options))
|
96
|
+
model_modal_body(model, edit_path, options)
|
97
|
+
concat(model_modal_footer(model, edit_path))
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def model_modal_header(model, edit_path, options = {})
|
102
|
+
content_tag(:div, class: 'modal-header') do
|
103
|
+
concat(content_tag(:h2) { model.name.titleize })
|
104
|
+
concat(tag(:button, class: 'btn-close', data: { bs_dismiss: :modal }, aria_label: :close))
|
97
105
|
end
|
98
106
|
end
|
99
107
|
|
108
|
+
def model_modal_body(model, edit_path, options = {})
|
109
|
+
concat(content_tag(:div, class: 'model-body') do
|
110
|
+
concat(model_modal_tabs(model, options))
|
111
|
+
concat(model_modal_tab_content(model, options))
|
112
|
+
end)
|
113
|
+
end
|
114
|
+
|
100
115
|
def model_modal_tabs(model, _options = {})
|
101
|
-
content_tag(:
|
102
|
-
concat(content_tag(:
|
103
|
-
|
104
|
-
content_tag(:a, href: "#field-tab-#{model.id}") { model.class.to_s.titleize }
|
105
|
-
end)
|
106
|
-
concat(content_tag(:li, class: 'tab') { content_tag(:a, href: "#standard-tab-#{model.id}") { 'Details' } })
|
107
|
-
if model.respond_to?(:logs)
|
108
|
-
concat(content_tag(:li, class: 'tab') { content_tag(:a, href: "#logs-tab-#{model.id}") { 'Logs' } })
|
109
|
-
end
|
116
|
+
content_tag(:ul, class: 'nav nav-tabs', data: { bs_toggle: :tabs }) do
|
117
|
+
concat(content_tag(:li, class: 'nav-item') do
|
118
|
+
content_tag(:a, class: 'nav-link active', href: "#field-tab-#{model.id}", data: { bs_toggle: :tab }) { model.class.to_s.titleize }
|
110
119
|
end)
|
120
|
+
concat(content_tag(:li, class: 'nav-item') do
|
121
|
+
content_tag(:a, class: 'nav-link', href: "#standard-tab-#{model.id}", data: { bs_toggle: :tab }) { 'Details' }
|
122
|
+
end)
|
123
|
+
if model.respond_to?(:logs)
|
124
|
+
concat(content_tag(:li, class: 'nav-item') do
|
125
|
+
content_tag(:a, class: 'nav-item', href: "#logs-tab-#{model.id}", data: { bs_toggler: :tab }) { 'Logs' }
|
126
|
+
end)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
def model_modal_tab_content(model, options = {})
|
132
|
+
content_tag(:div, class: 'tab-content') do
|
133
|
+
concat(model_modal_fields_tab(model, options))
|
134
|
+
concat(model_modal_standard_tab(model, options))
|
135
|
+
# concat(model_modal_logs_tab(model, options)) if model.respond_to?(:logs) && options[:show_audit_logs]
|
111
136
|
end
|
112
137
|
end
|
113
138
|
|
114
139
|
def model_modal_standard_tab(model, options = {})
|
115
|
-
content_tag(:div, id: "standard-tab-#{model.id}", class: '
|
116
|
-
concat(
|
140
|
+
content_tag(:div, id: "standard-tab-#{model.id}", class: 'tab-pane', role: :tabpanel) do
|
141
|
+
concat(model_modal_standard_fields(model, options))
|
117
142
|
end
|
118
143
|
end
|
119
144
|
|
120
145
|
def model_modal_fields_tab(model, options = {})
|
121
|
-
content_tag(:div, id: "field-tab-#{model.id}", class: '
|
146
|
+
content_tag(:div, id: "field-tab-#{model.id}", class: 'tab-pane active', role: :tabpanel) do
|
122
147
|
concat(model_modal_fields(model, options))
|
123
148
|
end
|
124
149
|
end
|
@@ -150,33 +175,28 @@ module ModelModalHelper
|
|
150
175
|
end
|
151
176
|
|
152
177
|
def model_modal_fields(model, _options = {})
|
153
|
-
content_tag(:
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
178
|
+
content_tag(:div, class: 'datagrid m-2') do
|
179
|
+
field_names = ((model.class.allowed_param_names) + %w(description name)).uniq.sort
|
180
|
+
field_names.each do |field_name|
|
181
|
+
next if model.respond_to?(field_name) && model.send(field_name).blank?
|
182
|
+
|
183
|
+
concat(model_modal_field(model, field_name))
|
184
|
+
end
|
159
185
|
end
|
160
186
|
end
|
161
187
|
|
162
|
-
def
|
163
|
-
content_tag(:
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
end
|
168
|
-
end)
|
188
|
+
def model_modal_standard_fields(model, _options = {})
|
189
|
+
content_tag(:div, class: 'datagrid m-2') do
|
190
|
+
model.class::STANDARD_FIELDS.each do |field_name|
|
191
|
+
concat(model_modal_field(model, field_name))
|
192
|
+
end
|
169
193
|
end
|
170
194
|
end
|
171
195
|
|
172
196
|
def model_modal_field(model, field_name)
|
173
|
-
content_tag(:
|
174
|
-
concat(content_tag(:
|
175
|
-
|
176
|
-
end)
|
177
|
-
concat(content_tag(:td) do
|
178
|
-
model_modal_field_value(model, field_name)
|
179
|
-
end)
|
197
|
+
content_tag(:div, class: 'datagrid-item') do
|
198
|
+
concat(content_tag(:div, class: 'datagrid-title') { field_name })
|
199
|
+
concat(content_tag(:div, class: 'datagrid-content') { model_modal_field_value(model, field_name) })
|
180
200
|
end
|
181
201
|
end
|
182
202
|
|
@@ -191,11 +211,11 @@ module ModelModalHelper
|
|
191
211
|
related_model.present? ? related_model.name : 'N/A'
|
192
212
|
end
|
193
213
|
when FalseClass
|
194
|
-
|
214
|
+
svg_icon(:x, color: :red)
|
195
215
|
when TrueClass
|
196
|
-
|
216
|
+
svg_icon(:check, color: :green)
|
197
217
|
when Mongoid::Boolean
|
198
|
-
value ?
|
218
|
+
value ? svg_icon(:check, color: :green) : svg_icon(:x, color: :red)
|
199
219
|
when Date, DateTime, Time
|
200
220
|
current_user.local_time(value, :long)
|
201
221
|
when Integer, Array, Hash, Float
|
@@ -207,7 +227,20 @@ module ModelModalHelper
|
|
207
227
|
|
208
228
|
def model_modal_footer(model, edit_path)
|
209
229
|
content_tag(:div, class: 'modal-footer') do
|
230
|
+
concat(content_tag(:button, class: 'btn me-auto', data: { bs_dismiss: :modal }) do
|
231
|
+
concat(I18n.t('ui_form.actions.close'))
|
232
|
+
concat(svg_icon(:close))
|
233
|
+
end)
|
210
234
|
concat(edit_modal_tag(model, edit_path))
|
211
235
|
end
|
212
236
|
end
|
237
|
+
|
238
|
+
def edit_modal_tag(obj, path, _options = {})
|
239
|
+
return unless can? :edit, obj
|
240
|
+
|
241
|
+
content_tag(:a, href: path, class: 'modal-action') do
|
242
|
+
concat(I18n.t('ui_form.actions.edit'))
|
243
|
+
concat(svg_icon(:edit))
|
244
|
+
end
|
245
|
+
end
|
213
246
|
end
|
@@ -2,9 +2,13 @@
|
|
2
2
|
module SvgIconHelper
|
3
3
|
# @abstract Render the appropriate icon based on the name and type
|
4
4
|
# @return [View]
|
5
|
-
def svg_icon(name, size: 24, type: :outline, classes: [], color: 'currentColor')
|
6
|
-
classes =
|
7
|
-
|
5
|
+
def svg_icon(name, size: 24, type: :outline, classes: [], color: 'currentColor', stroke_width: 2)
|
6
|
+
classes = if size <= 24
|
7
|
+
['icon', classes].compact.flatten.join(' ')
|
8
|
+
else
|
9
|
+
classes.compact.flatten.join(' ')
|
10
|
+
end
|
11
|
+
puts "key: #{key}"
|
8
12
|
(partial, stroke) = Rails.cache.fetch(key, expires_in: 1.hour) do
|
9
13
|
path_with_type = "icons/#{name}-#{type}"
|
10
14
|
path_without_type = "icons/#{name}"
|
@@ -27,12 +31,12 @@ module SvgIconHelper
|
|
27
31
|
class: classes,
|
28
32
|
fill: 'none',
|
29
33
|
stroke: stroke,
|
30
|
-
stroke_width:
|
34
|
+
stroke_width: stroke_width,
|
31
35
|
stroke_linecap: 'round',
|
32
36
|
stroke_linejoin: 'round') do
|
33
37
|
render partial
|
34
38
|
end
|
35
|
-
rescue StandardError
|
39
|
+
rescue StandardError
|
36
40
|
tag.svg(xmlns: "http://www.w3.org/2000/svg",
|
37
41
|
viewBox: "0 0 24 24",
|
38
42
|
width: size,
|
@@ -40,7 +44,7 @@ module SvgIconHelper
|
|
40
44
|
class: classes,
|
41
45
|
fill: 'none',
|
42
46
|
stroke: 'red',
|
43
|
-
stroke_width:
|
47
|
+
stroke_width: stroke_width,
|
44
48
|
stroke_linecap: 'round',
|
45
49
|
stroke_linejoin: 'round',
|
46
50
|
data: { bs_toggle: :tooltip },
|
data/config/locales/en.yml
CHANGED
@@ -10,24 +10,25 @@ module StandardModel
|
|
10
10
|
include Mongoid::Timestamps
|
11
11
|
include App47Logger
|
12
12
|
|
13
|
+
unless defined? FILER_NAMES
|
14
|
+
STANDARD_FIELDS = %w[created_at updated_at _type _id search_text sort_text last_modified_by_email
|
15
|
+
last_modified_by_name created_by_email created_by_name last_modified_by_id created_by_id
|
16
|
+
last_modified_by_type created_by_type].sort
|
17
|
+
end
|
18
|
+
|
13
19
|
def self.included(base)
|
14
20
|
base.class_eval do
|
15
|
-
#
|
21
|
+
# Constants
|
16
22
|
# Fields
|
17
|
-
#
|
18
23
|
field :last_modified_by_email, type: String
|
19
24
|
field :last_modified_by_name, type: String
|
20
25
|
field :created_by_email, type: String
|
21
26
|
field :created_by_name, type: String
|
22
|
-
#
|
23
27
|
# Relationships
|
24
|
-
#
|
25
28
|
belongs_to :last_modified_by, polymorphic: true, optional: true
|
26
29
|
belongs_to :created_by, polymorphic: true, optional: true
|
27
30
|
has_many Web47core::Config.audit_model_log_symbol, dependent: :nullify, inverse_of: :model
|
28
|
-
#
|
29
31
|
# Callbacks
|
30
|
-
#
|
31
32
|
after_save :clear_cache
|
32
33
|
before_destroy :clear_cache
|
33
34
|
before_save :capture_user_info
|
@@ -62,7 +63,7 @@ module StandardModel
|
|
62
63
|
#
|
63
64
|
def allowed_param_names(filter_names = [], include_relationships = true)
|
64
65
|
# Always filter out the mongoid reserved items
|
65
|
-
filter_names +=
|
66
|
+
filter_names += STANDARD_FIELDS
|
66
67
|
associations = many_to_many_associations
|
67
68
|
# filter out the relationship names so we don't have dups
|
68
69
|
associations.each { |association| filter_names << association.keys.first }
|
data/lib/web47core/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: web47core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.2.
|
4
|
+
version: 3.2.50
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Schroeder
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-08-
|
11
|
+
date: 2025-08-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -529,7 +529,11 @@ files:
|
|
529
529
|
- app/helpers/core_dropdown_helper.rb
|
530
530
|
- app/helpers/core_flash_toast_helper.rb
|
531
531
|
- app/helpers/core_floating_action_button_helper.rb
|
532
|
+
- app/helpers/core_form_checkbox_helper.rb
|
532
533
|
- app/helpers/core_form_helper.rb
|
534
|
+
- app/helpers/core_form_input_helper.rb
|
535
|
+
- app/helpers/core_form_select_helper.rb
|
536
|
+
- app/helpers/core_form_textarea_helper.rb
|
533
537
|
- app/helpers/core_helper.rb
|
534
538
|
- app/helpers/core_html5_form_helper.rb
|
535
539
|
- app/helpers/core_job_state_helper.rb
|