diff --git a/app/assets/stylesheets/dmpopidor.scss b/app/assets/stylesheets/dmpopidor.scss index 1dbb69f..e498acb 100644 --- a/app/assets/stylesheets/dmpopidor.scss +++ b/app/assets/stylesheets/dmpopidor.scss @@ -1163,6 +1163,21 @@ cursor: pointer; } } + &.select-field { + flex-direction: column; + .overridable-link { + float: left; + width: 100%; + } + .custom-value { + display: flex; + padding: 0; + label { + color: $blue; + margin-right: 5px; + } + } + } } fieldset { .intermediate-label { diff --git a/app/helpers/dynamic_form_helper.rb b/app/helpers/dynamic_form_helper.rb index 2e14f02..727b6e1 100644 --- a/app/helpers/dynamic_form_helper.rb +++ b/app/helpers/dynamic_form_helper.rb @@ -136,12 +136,13 @@ } end - def create_select_field(form, value, name, label, field_id, select_values, locale, required: false, validation: nil, html_class: nil, readonly: false, multiple: false, ttip: nil, default_value: nil) - render partial: "shared/dynamic_form/fields/select_field", + def create_simple_registry_field(form, value, form_prefix, property_name, label, field_id, select_values, locale, required: false, validation: nil, html_class: nil, readonly: false, multiple: false, ttip: nil, default_value: nil, overridable: nil) + render partial: "shared/dynamic_form/fields/registry/simple", locals: { f: form, selected_value: value, - field_name: name, + form_prefix: form_prefix, + property_name: property_name, field_label: label, select_values: select_values, locale: locale, @@ -152,7 +153,30 @@ required: required, validation: validation, ttip: ttip, - default_value: default_value + default_value: default_value, + overridable: overridable + } + end + + def create_complex_registry_field(form, value, form_prefix, property_name, label, field_id, select_values, locale, required: false, validation: nil, html_class: nil, readonly: false, multiple: false, ttip: nil, default_value: nil, overridable: nil) + render partial: "shared/dynamic_form/fields/registry/complex", + locals: { + f: form, + selected_value: value, + form_prefix: form_prefix, + property_name: property_name, + field_label: label, + select_values: select_values, + locale: locale, + field_class: html_class, + field_id: field_id, + multiple: multiple, + readonly: readonly, + required: required, + validation: validation, + ttip: ttip, + default_value: default_value, + overridable: overridable } end @@ -187,46 +211,55 @@ # Formats the data extract from the structured answer form to valid JSON data # This is useful because Rails converts all form data to strings and JSON needs the actual types def data_reformater(schema, data) + formated_data = {} schema["properties"].each do |key, prop| - next if data[key].nil? + next if data[key].nil? || key.end_with?("_custom") - if data[key] == "" - data[key] = nil - else - case prop["type"] - when "integer", "number" - data[key] = data[key].to_i - when "boolean" - data[key] = data[key] == "1" - when "array" - data[key] = data[key].is_a?(Array) ? data[key] : [data[key]] - when "object" - next if prop["schema_id"].nil? + case prop["type"] + when "integer", "number" + formated_data[key] = data[key].to_i + when "boolean" + formated_data[key] = data[key] == "1" + when "array" + formated_data[key] = data[key].is_a?(Array) ? data[key] : [data[key]] + when "object" + next if prop["schema_id"].nil? - sub_schema = MadmpSchema.find(prop["schema_id"]) + sub_schema = MadmpSchema.find(prop["schema_id"]) - if prop["inputType"].present? && prop["inputType"].eql?("pickOrCreate") - data[key] = { "dbid" => data[key].to_i } - elsif prop["registry_id"].present? - data[key] = data_reformater( - sub_schema.schema, - RegistryValue.find(data[key].to_i).data.merge( - "id": data[key].to_i - ) - ) - else - data[key] = data_reformater( - sub_schema.schema, - data[key] - ) + if prop["inputType"].present? && prop["inputType"].eql?("pickOrCreate") + formated_data[key] = { "dbid" => data[key].to_i } + elsif prop["registry_id"].present? + # if the field is overridable, check if there's a custom value + if prop["overridable"].present? && data["#{key}_custom"].present? + formated_data[key] = { "custom_value" => data["#{key}_custom"] } + next end - else - data[key] = data[key] - end + formated_data[key] = data_reformater( + sub_schema.schema, + RegistryValue.find(data[key].to_i).data.merge( + "id": data[key].to_i + ) + ) if data[key].present? + else + formated_data[key] = data_reformater( + sub_schema.schema, + data[key] + ) + end + else # type = string + # if the field is overridable, check if there's a custom value + if prop["overridable"].present? && data["#{key}_custom"].present? + formated_data[key] = data["#{key}_custom"] + next + end + formated_data[key] = data[key] end + + formated_data[key] = nil if formated_data[key].eql?("") end - data + formated_data end end diff --git a/app/javascript/views/shared/dynamic_form.js b/app/javascript/views/shared/dynamic_form.js index c69b991..3f9aff0 100644 --- a/app/javascript/views/shared/dynamic_form.js +++ b/app/javascript/views/shared/dynamic_form.js @@ -70,3 +70,21 @@ .toggleClass('fa-chevron-right') .toggleClass('fa-chevron-left'); }); + +$(document).on('click', '.select-field .overridable-link', (e) => { + e.preventDefault(); + const target = $(e.target); + const selectField = target.parent(); + + selectField.find('.custom-value').show(); + selectField.find('.custom-value input').val(''); + selectField.find('select').val(''); +}); + +$(document).on('change', '.select-field select', (e) => { + const target = $(e.target); + const selectField = target.parent(); + + selectField.find('.custom-value').hide(); + selectField.find('.custom-value input').val(''); +}); diff --git a/app/models/madmp_fragment.rb b/app/models/madmp_fragment.rb index 8c10f0c..76ab0d2 100644 --- a/app/models/madmp_fragment.rb +++ b/app/models/madmp_fragment.rb @@ -170,35 +170,25 @@ children = self.children editable_data = data editable_data.each do |prop, value| - case value - when Hash - if value["dbid"].present? - child_data = children.exists?(value["dbid"]) ? children.find(value["dbid"]) : MadmpFragment.find(value["dbid"]) - editable_data = editable_data.merge( - { - prop => child_data.get_full_fragment - } - ) - end - when Array - unless value.length.zero? - fragment_tab = [] - value.each do |v| - next if v.nil? + if value.is_a?(Hash) && value["dbid"].present? + child = children.exists?(value["dbid"]) ? children.find(value["dbid"]) : MadmpFragment.find(value["dbid"]) + child_data = child.additional_info["custom_value"].present? ? child.additional_info["custom_value"] : child.get_full_fragment + editable_data = editable_data.merge(prop => child_data) + end - if v.instance_of?(Hash) && v["dbid"].present? - child_data = children.exists?(v["dbid"]) ? children.find(v["dbid"]) : MadmpFragment.find(v["dbid"]) - fragment_tab.push(child_data.get_full_fragment) - else - fragment_tab.push(v) - end + if value.is_a?(Array) && !value.empty? + fragment_tab = [] + value.each do |v| + next if v.nil? + + if v.is_a?(Hash) && v["dbid"].present? + child_data = children.exists?(v["dbid"]) ? children.find(v["dbid"]) : MadmpFragment.find(v["dbid"]) + fragment_tab.push(child_data.get_full_fragment) + else + fragment_tab.push(v) end - editable_data = editable_data.merge( - { - prop => fragment_tab - } - ) end + editable_data = editable_data.merge(prop => fragment_tab) end end editable_data @@ -271,6 +261,13 @@ if param_data.present? && param_data[prop].present? if schema_prop.key?("inputType") && schema_prop["inputType"].eql?("pickOrCreate") fragmented_data[prop] = content + elsif schema_prop["overridable"].present? && param_data[prop]["custom_value"].present? + # if the property is overridable & value is custom, take the value as is + sub_fragment = MadmpFragment.find(data[prop]["dbid"]) + sub_fragment.update( + data: {}, + additional_info: sub_fragment.additional_info.merge(sub_data) + ) elsif data[prop]["dbid"] sub_fragment = MadmpFragment.find(data[prop]["dbid"]) sub_fragment.save_as_multifrag(sub_data, sub_schema) @@ -280,7 +277,10 @@ fragmented_data[prop] = content end end - update!(data: data.merge(fragmented_data)) + update!( + data: data.merge(fragmented_data), + additional_info: additional_info.except!("custom_value") + ) end def self.find_sti_class(type_name) diff --git a/app/models/madmp_schema.rb b/app/models/madmp_schema.rb index abf8e84..d31f09c 100644 --- a/app/models/madmp_schema.rb +++ b/app/models/madmp_schema.rb @@ -101,14 +101,16 @@ parameters.append(key) elsif prop["registry_id"].present? parameters.append(key) + parameters.append("#{key}_custom") if prop["overridable"].present? else sub_schema = MadmpSchema.find(prop["schema_id"]) parameters.append(key => sub_schema.generate_strong_params(false)) end elsif prop["type"] == "array" && !flat - parameters.append({ key => [] }) + parameters.append(key => []) else parameters.append(key) + parameters.append("#{key}_custom") if prop["overridable"].present? end end parameters diff --git a/app/views/branded/shared/dynamic_form/_form.html.erb b/app/views/branded/shared/dynamic_form/_form.html.erb index df577be..da050dc 100644 --- a/app/views/branded/shared/dynamic_form/_form.html.erb +++ b/app/views/branded/shared/dynamic_form/_form.html.erb @@ -30,6 +30,7 @@ <%# REGISTRIES %> <%# ############################### %> <% if prop['registry_id'].present? && prop['inputType'] == 'dropdown' %> + <% overridable = prop["overridable"] unless prop["overridable"].nil? %> <% if prop['schema_id'].present? && prop["type"].eql?('object') %> <%# Complex registries (value in an object) %> <% registryValues = RegistryValue.where(registry_id: prop['registry_id'])%> @@ -48,17 +49,17 @@ <%= d_('dmpopidor', '- or change the selected value -') %> <% end %> - <%= create_select_field(f, nil, "#{f.object_name}[#{field_name}]", nil, field_id, registryValues, template_locale, readonly: readonly, multiple: false, validation: validation, ttip: ttip, default_value: default_value) %> + <%= create_complex_registry_field(f, value, form_prefix, key, nil, field_id, registryValues, template_locale, readonly: readonly, multiple: false, validation: validation, ttip: ttip, default_value: default_value, overridable: overridable) %> <% elsif prop["type"].eql?('string')%> <%# Simple registries (value in a string) %> <% registryValues = RegistryValue.where(registry_id: prop['registry_id'])%> - <%= create_select_field(f, value, "#{f.object_name}[#{field_name}]", label, field_id, registryValues, template_locale, readonly: readonly, validation: validation, ttip: ttip, default_value: default_value) %> + <%= create_simple_registry_field(f, value, form_prefix, key, label, field_id, registryValues, template_locale, readonly: readonly, validation: validation, ttip: ttip, default_value: default_value, overridable: overridable) %> <% elsif prop["type"].eql?('array')%> <%# Select 'multiple' from simple registry where the user can choose multiple options %> <% registryValues = RegistryValue.where(registry_id: prop['registry_id'])%> - <%= create_select_field(f, value, "#{f.object_name}[#{field_name}]", label, field_id, registryValues, template_locale, readonly: readonly, multiple: true, validation: validation, ttip: ttip, default_value: default_value) %> + <%= create_simple_registry_field(f, value, form_prefix, key, label, field_id, registryValues, template_locale, readonly: readonly, multiple: true, validation: validation, ttip: ttip, default_value: default_value, overridable: overridable) %> <% end %> <% next %> diff --git a/app/views/branded/shared/dynamic_form/_modal.html.erb b/app/views/branded/shared/dynamic_form/_modal.html.erb index 2e8835d..094be43 100644 --- a/app/views/branded/shared/dynamic_form/_modal.html.erb +++ b/app/views/branded/shared/dynamic_form/_modal.html.erb @@ -31,6 +31,7 @@ question_id: nil, classname: @classname, readonly: @readonly, + form_prefix: nil, template_locale: @template_locale })%> diff --git a/app/views/branded/shared/dynamic_form/fields/_select_field.html.erb b/app/views/branded/shared/dynamic_form/fields/_select_field.html.erb deleted file mode 100644 index 4a37f62..0000000 --- a/app/views/branded/shared/dynamic_form/fields/_select_field.html.erb +++ /dev/null @@ -1,33 +0,0 @@ -<%# locals: { f, field_label, field_name, select_values, locale, selected_value, field_class, required, readonly, multiple, validation, ttip } %> -<% selected_value ||= default_value %> -<% include_blank = !selected_value && !default_value %> - -<% unless field_label.nil?%> - <% field_label = required ? "* #{field_label}" : field_label%> - -
- <%= f.label field_id, field_label, class: 'control-label' %> -
-<% end %> -
- <%= select_tag field_name, - options_for_select( - select_values.map {|v| [ - v.to_s(locale), - select_value(v, locale) - ] - }, - selected: selected_value - ), - disabled: readonly, - multiple: multiple, - include_blank: d_("dmpopidor", "Please select a value from the list."), - "data-toggle": "tooltip", - title: ttip, - class: "form-control #{field_class}", - id: field_id %> - <%= render partial: "shared/dynamic_form/validation_indicator", locals: { - validation: validation - } unless validation == "none" - %> -
\ No newline at end of file diff --git a/app/views/branded/shared/dynamic_form/fields/registry/_complex.html.erb b/app/views/branded/shared/dynamic_form/fields/registry/_complex.html.erb new file mode 100644 index 0000000..528177a --- /dev/null +++ b/app/views/branded/shared/dynamic_form/fields/registry/_complex.html.erb @@ -0,0 +1,53 @@ +<%# locals: { f, field_label, form_prefix, property_name, select_values, locale, selected_value, field_class, required, readonly, multiple, validation, ttip, default_value, overridable } %> +<% selected_value ||= default_value %> +<% include_blank = !selected_value && !default_value %> +<% field_name = defined?(form_prefix) ? "#{form_prefix}[#{property_name}]" : property_name %> + +<% unless field_label.nil? %> + <% field_label = required ? "* #{field_label}" : field_label%> + +
+ <%= f.label field_id, field_label, class: 'control-label' %> +
+<% end %> +
+ <%= select_tag "#{f.object_name}[#{field_name}]", + options_for_select( + select_values.map {|v| [ + v.to_s(locale), + select_value(v, locale) + ] + }, + selected: selected_value + ), + disabled: readonly, + multiple: multiple, + include_blank: d_("dmpopidor", "Please select a value from the list."), + "data-toggle": "tooltip", + title: ttip, + class: "form-control #{field_class}", + id: field_id %> + <%= render partial: "shared/dynamic_form/validation_indicator", locals: { + validation: validation + } unless validation == "none" %> + + <% if overridable %> + <% + style = 'display: none;' + custom_value = nil + if selected_value.additional_info["custom_value"].present? + style = '' + custom_value = selected_value.additional_info["custom_value"] + end + %> + <% other_field_name = defined?(form_prefix) ? "#{form_prefix}[#{property_name}_custom]" : "#{property_name}_custom" %> + <%= d_('dmpopidor', 'Element is not in the list.') %> +
+ <%= f.label other_field_name, d_("dmpopidor", "Custom value: "), class: 'control-label' %> + <%= f.text_field other_field_name, + value: custom_value, + class: "form-control #{field_class}", + id: field_id %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/views/branded/shared/dynamic_form/fields/registry/_simple.html.erb b/app/views/branded/shared/dynamic_form/fields/registry/_simple.html.erb new file mode 100644 index 0000000..16bd0e8 --- /dev/null +++ b/app/views/branded/shared/dynamic_form/fields/registry/_simple.html.erb @@ -0,0 +1,53 @@ +<%# locals: { f, field_label, form_prefix, property_name, select_values, locale, selected_value, field_class, required, readonly, multiple, validation, ttip, default_value, overridable } %> +<% selected_value ||= default_value %> +<% include_blank = !selected_value && !default_value %> +<% field_name = defined?(form_prefix) ? "#{form_prefix}[#{property_name}]" : property_name %> + +<% unless field_label.nil? %> + <% field_label = required ? "* #{field_label}" : field_label%> + +
+ <%= f.label field_id, field_label, class: 'control-label' %> +
+<% end %> +
+ <%= select_tag "#{f.object_name}[#{field_name}]", + options_for_select( + select_values.map {|v| [ + v.to_s(locale), + select_value(v, locale) + ] + }, + selected: selected_value + ), + disabled: readonly, + multiple: multiple, + include_blank: d_("dmpopidor", "Please select a value from the list."), + "data-toggle": "tooltip", + title: ttip, + class: "form-control #{field_class}", + id: field_id %> + <%= render partial: "shared/dynamic_form/validation_indicator", locals: { + validation: validation + } unless validation == "none" %> + + <% if overridable %> + <% + style = '' + custom_value = selected_value + if select_values.any? { |r| select_value(r, locale) == selected_value } + style = 'display: none;' + custom_value = nil + end + %> + <% other_field_name = defined?(form_prefix) ? "#{form_prefix}[#{property_name}_custom]" : "#{property_name}_custom" %> + <%= d_('dmpopidor', 'Element is not in the list.') %> +
+ <%= f.label other_field_name, d_("dmpopidor", "Custom value: "), class: 'control-label' %> + <%= f.text_field other_field_name, + value: custom_value, + class: "form-control #{field_class}", + id: field_id %> +
+ <% end %> +
\ No newline at end of file diff --git a/config/locale/dmpopidor.pot b/config/locale/dmpopidor.pot index 10eeaa5..091f093 100644 --- a/config/locale/dmpopidor.pot +++ b/config/locale/dmpopidor.pot @@ -526,3 +526,9 @@ msgid "Plan Title" msgstr "" +msgid "Element is not in the list." +msgstr "" + +msgid "Custom value: " +msgstr "" + diff --git a/config/locale/en_GB/dmpopidor.po b/config/locale/en_GB/dmpopidor.po index 4561ef9..a71ca1f 100644 --- a/config/locale/en_GB/dmpopidor.po +++ b/config/locale/en_GB/dmpopidor.po @@ -516,4 +516,10 @@ msgstr "Comments & Guidance" msgid "Plan Title" -msgstr "Plan Title" \ No newline at end of file +msgstr "Plan Title" + +msgid "Element is not in the list." +msgstr "Element is not in the list." + +msgid "Custom value: " +msgstr "Custom value: " \ No newline at end of file diff --git a/config/locale/fr_FR/dmpopidor.po b/config/locale/fr_FR/dmpopidor.po index 9970d8e..73eb1c9 100644 --- a/config/locale/fr_FR/dmpopidor.po +++ b/config/locale/fr_FR/dmpopidor.po @@ -518,4 +518,10 @@ msgstr "Commentaires & Recommandations" msgid "Plan Title" -msgstr "Titre du plan" \ No newline at end of file +msgstr "Titre du plan" + +msgid "Element is not in the list." +msgstr "L'élément n'est pas dans la liste." + +msgid "Custom value: " +msgstr "Valeur personnalisée : " \ No newline at end of file diff --git a/lib/dmpopidor/models/plan.rb b/lib/dmpopidor/models/plan.rb index 78f9032..27f4f79 100644 --- a/lib/dmpopidor/models/plan.rb +++ b/lib/dmpopidor/models/plan.rb @@ -225,7 +225,6 @@ meta_fragment.madmp_schema.schema, meta ) - project_data = data_reformater( project_fragment.madmp_schema.schema, project