Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

I144 form control redux #212

Open
wants to merge 4 commits into
base: i144-form-control
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 58 additions & 62 deletions hyrax/app/assets/javascripts/hyrax/save_work/required_fields.es6
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
jQuery.fn.hasVal = function() {
return this !== null && this.val().length > 0;
}

export class RequiredFields {
// Monitors the form and runs the callback if any of the required fields change
constructor(form, callback) {
Expand All @@ -7,80 +11,72 @@ export class RequiredFields {
}

get areComplete() {
this.reload()
return this.requiredFields.filter((n, elem) => { return this.isValuePresent(elem) } ).length === 0
var missing = this.requiredFields.filter((n, elem) => { return this.isRequiredButBlank(elem) } )
return missing.length === 0
}

requiredIf() {
// this is hard-coded - to do, use erb to grab a list
let conditions = ['any', 'name']
var elems = []

// build the list of elem; cleanup
$.each(conditions, function(n,value) {
$(":input.require-if-"+value).each(function(n,elem) {
// Remove the required class, attribute and box-shadow (they will be reset if needed)
$(elem).removeClass('required');
$(elem).attr('required', null);
$(elem).removeAttr('style');
elems.push({ value : elem })
});
});
// helper to clear the 'required' styling
notRequired(elem, label) {
$(label).removeClass('required')
$(label).find('span').remove()

$.each(elems, function(n,elem_obj) {
var required = elem_obj.value
var id = $(required).attr('id');
var parents = $(required).closest('div.multi-nested')
$(elem).removeClass('required');
$(elem).attr('required', null);
$(elem).removeAttr('style');
}

if (elem_obj.key === 'any') {
var label = $(parents).find('label[for="' + id + '_"]')
} else {
var label = $(parents).find('label[for="' + id + '_' + elem_obj.key + '"]')
}
required(elem, label) {
$(label).addClass('required control-label')
$(label).append('<span class="label label-info required-tag">required</span>')
$(elem).addClass('required');
$(elem).attr('required', 'required');
$(elem).css('box-shadow','0px 0px 0px 2px red');
}

// Remove the required class and span (they will be reset if needed)
$(label).removeClass('required')
$(label).find('span').remove();

// Find the immediate field-wrapper
// Gather the inputs
this.inputs = $(required).closest('li.field-wrapper').find(':input');
// Skip the current elem, any hidden fields and any buttons, skip operator (role), Processed (date) (pre-filled but should not be required)
if (this.inputs.filter((n, el) => {
if (
!el.parentNode.className.includes("hidden") && !el.className.includes('btn') && !el.className.includes('remove-hidden') && el != required && el.value !== 'operator' && el.value !== 'Processed' ) {
return (el.value !== '');
}
} ).length > 0) {
// Add the required classes, attributes and labels
if ( $(label).has('span').length === 0 ) {
$(label).addClass('required control-label')
$(label).append('<span class="label label-info required-tag">required</span>');
$(required).addClass('required');
$(required).attr('required', 'required');
// Only add the css if the value is empty
if ( ($(required).val() === null) || ($(required).val().length < 1) ) {
$(required).css('box-shadow','0px 0px 0px 2px red');
}
}
};
});
isRequiredButBlank(elem) {
// if the value is filled in, do not check further
if($(elem).hasVal()) return false

// Find all inputs in multi-nested blocks (where conditional requirements will be in place)
this.conditionalRequiredFields = this.form.find('div.multi-nested :input')
this.conditionalRequiredFields.change(this.callback)
}
var requiredButBlank = false
if($(elem).data('required')){
var requirements = $(elem).data('required').split(';')

// Special "any" case
if(requirements.includes('any')){
$(elem).parents('.form-group').find(':input').not('[type=hidden], [data-skip=true]').each(function(i) {
if($(this).hasVal()) return (requiredButBlank = true)
})
} else {
// Go through each requirement
$.each(requirements, function(i, e) {
if($(`input[data-name=${e}]`).hasVal()) return (requiredButBlank = true)
})
}

// TODO this label replace is not right, but ids with [] are not allowed in htlm
// and need to be fixed in the nested inputs. Jquery throws an exeption if we try
// to match on for block with square brackets
var elem_id = elem.id.replace(/\[|\]/g, '_')
var label = $(`label[for=${elem_id.replace(/__/g, '_')}]`)
// var label = $(`label[for=${elem.id.replace(/\[|\]/g, '_')}]`)

isValuePresent(elem) {
return ($(elem).val() === null) || ($(elem).val().length < 1)
// only run css updates if they are needed, as they are expensive
// this first one never gets called
if(!requiredButBlank && label.hasClass('required')) {
this.notRequired(elem, label)
} else if( requiredButBlank && !label.hasClass('required')) {
this.required(elem, label)
}
return requiredButBlank
} else {
return true
}
}

// Reassign requiredFields because fields may have been added or removed.
reload() {
// Add any new required flags
this.requiredIf()
// ":input" matches all input, select or textarea fields.
this.requiredFields = this.form.find(':input[required]')
this.requiredFields = this.form.find(':input[required], :input.required-if')
this.requiredFields.change(this.callback)
}
}
2 changes: 1 addition & 1 deletion hyrax/app/forms/hyrax/dataset_form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class DatasetForm < Hyrax::Forms::WorkForm
:title]

self.required_fields += [
# # Adding all required fields in order of display in form
# Adding all required fields in order of display in form
:supervisor_approval, :title, :data_origin
]

Expand Down
5 changes: 3 additions & 2 deletions hyrax/app/inputs/nested_affiliation_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: required)
out << template.label_tag(field_id, field.to_s.humanize, required: required)
out << ' </div>'

out << " <div class='col-md-9'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class))
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class, data: {required: field_requirements, name: field}))
out << ' </div>'
out << '</div>'

Expand Down
18 changes: 12 additions & 6 deletions hyrax/app/inputs/nested_attributes_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,15 +118,21 @@ def id_for(attribute_name, index, field, [email protected]_name)
end

def class_for(attribute_name, field, [email protected]_class)
requirements = model_class.requirements_for(attribute_name)
if (requirements[:required] && requirements[:required].flatten.include?(field.to_s)) ||
(requirements[:conditional] && requirements[:conditional][field].present?)
'required-if'
else
''
end
end

def requirements_for(attribute_name, field, [email protected]_class)
requirements = model_class.requirements_for(attribute_name)
if requirements[:required] && requirements[:required].flatten.include?(field.to_s)
'require-if-any'
'any'
elsif requirements[:conditional] && requirements[:conditional][field].present?
cl = []
requirements[:conditional][field].each do | conditional_field |
cl << "require-if-#{conditional_field}"
end
cl.join(' ')
requirements[:conditional][field].join(';')
end
end
end
5 changes: 3 additions & 2 deletions hyrax/app/inputs/nested_chemical_composition_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: required)
out << template.label_tag(field_id, field.to_s.humanize, required: required)
out << ' </div>'

out << " <div class='col-md-6'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class))
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class, data: {required: field_requirements, name: field}))
out << ' </div>'

# --- delete checkbox
Expand Down
5 changes: 3 additions & 2 deletions hyrax/app/inputs/nested_crystallographic_structure_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,15 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: required)
out << template.label_tag(field_id, field.to_s.humanize, required: required)
out << ' </div>'

out << " <div class='col-md-6'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class))
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class, data: {required: field_requirements, name: field}))
out << ' </div>'

# --- delete checkbox
Expand Down
11 changes: 7 additions & 4 deletions hyrax/app/inputs/nested_custom_property_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)


out << "<div class='row'>"
out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: required)
out << template.label_tag(field_id, field.to_s.humanize, required: required)
out << ' </div>'

out << " <div class='col-md-9'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id, required: required, class: field_class))
options.merge(value: field_value, name: field_name, id: field_id, required: required, class: field_class, data: {required: field_requirements, name: field}))
out << ' </div>'
out << '</div>' # row

Expand All @@ -42,14 +44,15 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: false)
out << template.label_tag(field_id, field.to_s.humanize, required: false)
out << ' </div>'

out << " <div class='col-md-6'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id, class: field_class))
options.merge(value: field_value, name: field_name, id: field_id, class: field_class, data: {required: field_requirements, name: field}))
out << ' </div>'

# --- delete checkbox
Expand Down
7 changes: 5 additions & 2 deletions hyrax/app/inputs/nested_date_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

date_options = DateService.new.select_all_options
out << " <div class='col-md-3'>"
out << template.select_tag(field_name, template.options_for_select(date_options, field_value),
label: '', class: 'select form-control', prompt: 'choose type', id: field_id)
label: '', class: 'select form-control', prompt: 'choose type', id: field_id, data: {required: field_requirements, name: field, skip: true})
out << ' </div>'

# --- date
Expand All @@ -36,11 +38,12 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << " <div class='col-md-6'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id,
data: { provide: 'datepicker' }, required: required, class: field_class))
data: { provide: 'datepicker', required: field_requirements, name: field }, required: required, class: field_class))
out << ' </div>'

# --- delete checkbox
Expand Down
25 changes: 15 additions & 10 deletions hyrax/app/inputs/nested_event_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << "<div class='row'>"
out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: required)
out << template.label_tag(field_id, field.to_s.humanize, required: required)
out << ' </div>'

out << " <div class='col-md-9'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id, required: required, class: field_class))
options.merge(value: field_value, name: field_name, id: field_id, required: required, class: field_class, data: {required: field_requirements, name: field}))
out << ' </div>'
out << '</div>' # row

Expand All @@ -34,15 +35,16 @@ def build_components(attribute_name, value, index, options, [email protected]
field_name = name_for(attribute_name, index, field, parent)
field_id = id_for(attribute_name, index, field, parent)
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << "<div class='row'>"
out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: false)
out << template.label_tag(field_id, field.to_s.humanize, required: false)
out << ' </div>'

out << " <div class='col-md-9'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class))
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class, data: {required: field_requirements, name: field}))
out << ' </div>'
out << '</div>' # row

Expand All @@ -52,16 +54,17 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << "<div class='row'>"
out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: false)
out << template.label_tag(field_id, field.to_s.humanize, required: false)
out << ' </div>'

out << " <div class='col-md-9'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id,
data: { provide: 'datepicker' }, required: false, class: field_class))
data: { provide: 'datepicker', required: field_requirements, name: field }, required: false, class: field_class))
out << ' </div>'
out << '</div>' # row

Expand All @@ -71,16 +74,17 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << "<div class='row'>"
out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: false)
out << template.label_tag(field_id, field.to_s.humanize, required: false)
out << ' </div>'

out << " <div class='col-md-9'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id,
data: { provide: 'datepicker' }, required: false, class: field_class))
data: { provide: 'datepicker', required: field_requirements, name: field }, required: false, class: field_class))
out << ' </div>'
out << '</div>' # row

Expand All @@ -93,14 +97,15 @@ def build_components(attribute_name, value, index, options, [email protected]
field_id = id_for(attribute_name, index, field, parent)
field_value = value.send(field).first
field_class = class_for(attribute_name, field)
field_requirements = requirements_for(attribute_name, field)

out << " <div class='col-md-3'>"
out << template.label_tag(field_name, field.to_s.humanize, required: false)
out << template.label_tag(field_id, field.to_s.humanize, required: false)
out << ' </div>'

out << " <div class='col-md-6'>"
out << @builder.text_field(field_name,
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class))
options.merge(value: field_value, name: field_name, id: field_id, required: false, class: field_class, data: {required: field_requirements, name: field}))
out << ' </div>'

# --- delete checkbox
Expand Down
Loading