diff --git a/app/assets/stylesheets/new_design/forms.scss b/app/assets/stylesheets/new_design/forms.scss index aa201b22d..031c11f83 100644 --- a/app/assets/stylesheets/new_design/forms.scss +++ b/app/assets/stylesheets/new_design/forms.scss @@ -44,6 +44,12 @@ } } + .form-label { + font-weight: bold; + font-size: 18px; + margin-bottom: $default-padding; + } + .notice { @include notice-text-style; margin-top: - $default-spacer; diff --git a/app/assets/stylesheets/new_design/invites_form.scss b/app/assets/stylesheets/new_design/invites_form.scss index 81580da30..2cd6e65e3 100644 --- a/app/assets/stylesheets/new_design/invites_form.scss +++ b/app/assets/stylesheets/new_design/invites_form.scss @@ -26,7 +26,7 @@ input[type=email] { width: auto; - margin-bottom: 0; + margin-bottom: $default-spacer; } .button { diff --git a/app/assets/stylesheets/new_design/new_header.scss b/app/assets/stylesheets/new_design/new_header.scss index 5dd761b73..27cac962d 100644 --- a/app/assets/stylesheets/new_design/new_header.scss +++ b/app/assets/stylesheets/new_design/new_header.scss @@ -2,6 +2,7 @@ @import "common"; @import "constants"; @import "mixins"; +@import "utils"; $header-landing-breakpoint: 1040px; $header-mobile-breakpoint: 550px; @@ -148,6 +149,10 @@ $header-mobile-breakpoint: 550px; margin: 0; } + label.hidden { + @extend .hidden; + } + button { @extend %outline; diff --git a/app/models/champ.rb b/app/models/champ.rb index 69c6303e3..35936912b 100644 --- a/app/models/champ.rb +++ b/app/models/champ.rb @@ -80,6 +80,10 @@ class Champ < ApplicationRecord type_de_champ.to_typed_id end + def html_label? + true + end + private def needs_dossier_id? diff --git a/app/models/champs/civilite_champ.rb b/app/models/champs/civilite_champ.rb index 9404e46a1..600a2c032 100644 --- a/app/models/champs/civilite_champ.rb +++ b/app/models/champs/civilite_champ.rb @@ -1,2 +1,5 @@ class Champs::CiviliteChamp < Champ + def html_label? + false + end end diff --git a/app/models/champs/datetime_champ.rb b/app/models/champs/datetime_champ.rb index 84008894b..7f09acee1 100644 --- a/app/models/champs/datetime_champ.rb +++ b/app/models/champs/datetime_champ.rb @@ -13,6 +13,10 @@ class Champs::DatetimeChamp < Champ value.present? ? I18n.l(Time.zone.parse(value)) : "" end + def html_label? + false + end + private def format_before_save diff --git a/app/models/champs/piece_justificative_champ.rb b/app/models/champs/piece_justificative_champ.rb index 35403deb6..431a86e94 100644 --- a/app/models/champs/piece_justificative_champ.rb +++ b/app/models/champs/piece_justificative_champ.rb @@ -51,4 +51,8 @@ class Champs::PieceJustificativeChamp < Champ piece_justificative_file.service_url end end + + def html_label? + false + end end diff --git a/app/views/invites/_form.html.haml b/app/views/invites/_form.html.haml index 7936bc7ce..5ebaeca70 100644 --- a/app/views/invites/_form.html.haml +++ b/app/views/invites/_form.html.haml @@ -15,8 +15,12 @@ = form_tag dossier_invites_path(dossier), remote: true, method: :post, class: 'form' do .row .col - = email_field_tag :invite_email, '', class: 'small', placeholder: 'adresse email', required: true + %span + = label_tag :invite_email, "Adresse email" + = email_field_tag :invite_email, '', class: 'small', placeholder: 'Adresse email', required: true .col + %span + = label_tag :invite_message, "Ajouter un message à la personne invitée (optionnel)" = text_area_tag :invite_message, '', class: 'small', placeholder: 'Ajouter un message à la personne invitée (optionnel)' .col = submit_tag 'Envoyer une invitation', class: 'button accepted' diff --git a/app/views/layouts/_account_dropdown.haml b/app/views/layouts/_account_dropdown.haml index a897363a7..e826f372c 100644 --- a/app/views/layouts/_account_dropdown.haml +++ b/app/views/layouts/_account_dropdown.haml @@ -1,5 +1,6 @@ .dropdown.header-menu-opener %button.button.dropdown-button.header-menu-button{ title: "Mon compte" } + .hidden Mon compte = image_tag "icons/account-circle.svg", alt: '' %ul.header-menu.dropdown-content %li diff --git a/app/views/layouts/_new_header.haml b/app/views/layouts/_new_header.haml index fae04f47a..e172edf61 100644 --- a/app/views/layouts/_new_header.haml +++ b/app/views/layouts/_new_header.haml @@ -47,9 +47,10 @@ %li .header-search{ role: 'search' } = form_tag recherche_dossiers_path, method: :post, class: "form" do + = label_tag :dossier_id, "Numéro de dossier", class: 'hidden' = text_field_tag :dossier_id, "", placeholder: "Numéro de dossier" %button{ title: "Rechercher" } - = image_tag "icons/search-blue.svg", alt: '' + = image_tag "icons/search-blue.svg", alt: 'Rechercher', 'aria-hidden':'true' - if instructeur_signed_in? || user_signed_in? %li diff --git a/app/views/shared/dossiers/editable_champs/_champ_label.html.haml b/app/views/shared/dossiers/editable_champs/_champ_label.html.haml index 4ca8243dc..737846f64 100644 --- a/app/views/shared/dossiers/editable_champs/_champ_label.html.haml +++ b/app/views/shared/dossiers/editable_champs/_champ_label.html.haml @@ -1,11 +1,10 @@ -= form.label champ.main_value_name do - #{champ.libelle} - - if champ.mandatory? - %span.mandatory * - - - if champ.updated_at.present? && seen_at.present? - %span.updated-at{ class: highlight_if_unseen_class(seen_at, champ.updated_at) } - = "modifié le #{try_format_datetime(champ.updated_at)}" += # we do this trick because some html elements should use 'label' and some should be plain paragraphs +- if champ.html_label? + = form.label champ.main_value_name do + = render partial: 'shared/dossiers/editable_champs/champ_label_content', locals: { champ: champ, seen_at: seen_at } +- else + %h4.form-label + = render partial: 'shared/dossiers/editable_champs/champ_label_content', locals: { champ: champ, seen_at: seen_at } - if champ.description.present? .notice{ id: describedby_id(champ) }= string_to_html(champ.description) diff --git a/app/views/shared/dossiers/editable_champs/_champ_label_content.html.haml b/app/views/shared/dossiers/editable_champs/_champ_label_content.html.haml new file mode 100644 index 000000000..7174f7ee5 --- /dev/null +++ b/app/views/shared/dossiers/editable_champs/_champ_label_content.html.haml @@ -0,0 +1,7 @@ +#{champ.libelle} +- if champ.mandatory? + %span.mandatory * + +- if champ.updated_at.present? && seen_at.present? + %span.updated-at{ class: highlight_if_unseen_class(seen_at, champ.updated_at) } + = "modifié le #{try_format_datetime(champ.updated_at)}" diff --git a/app/views/shared/dossiers/editable_champs/_civilite.html.haml b/app/views/shared/dossiers/editable_champs/_civilite.html.haml index b20e50673..9c4d3bfac 100644 --- a/app/views/shared/dossiers/editable_champs/_civilite.html.haml +++ b/app/views/shared/dossiers/editable_champs/_civilite.html.haml @@ -1,4 +1,6 @@ -.radios +%fieldset.radios + %legend.mandatory-explanation + Sélectionnez une des valeurs %label = form.radio_button :value, Individual::GENDER_MALE Monsieur diff --git a/app/views/shared/dossiers/editable_champs/_linked_drop_down_list.html.haml b/app/views/shared/dossiers/editable_champs/_linked_drop_down_list.html.haml index fcabeefa9..259aa3bc1 100644 --- a/app/views/shared/dossiers/editable_champs/_linked_drop_down_list.html.haml +++ b/app/views/shared/dossiers/editable_champs/_linked_drop_down_list.html.haml @@ -3,6 +3,8 @@ champ.primary_options, { required: champ.mandatory? }, { data: { secondary_options: champ.secondary_options } } + %span + = form.label :secondary_value, "Valeur secondaire dépendant de la première", class: 'hidden' = form.select :secondary_value, champ.secondary_options[champ.primary_value], { required: champ.mandatory? }, diff --git a/app/views/shared/dossiers/editable_champs/_yes_no.html.haml b/app/views/shared/dossiers/editable_champs/_yes_no.html.haml index 0d8b3bcb0..11cd71ad0 100644 --- a/app/views/shared/dossiers/editable_champs/_yes_no.html.haml +++ b/app/views/shared/dossiers/editable_champs/_yes_no.html.haml @@ -1,4 +1,6 @@ -.radios +%fieldset.radios + %legend.mandatory-explanation + Sélectionnez une des deux valeurs %label = form.radio_button :value, true Oui diff --git a/app/views/users/dossiers/identite.html.haml b/app/views/users/dossiers/identite.html.haml index bf151d17f..a180c1585 100644 --- a/app/views/users/dossiers/identite.html.haml +++ b/app/views/users/dossiers/identite.html.haml @@ -8,7 +8,7 @@ %p.mb-1 Merci de remplir vos informations personnelles pour accéder à la démarche. - %label + %span.form-label %span.mandatory * champs requis diff --git a/config/initializers/date_select.rb b/config/initializers/date_select.rb new file mode 100644 index 000000000..8418f043a --- /dev/null +++ b/config/initializers/date_select.rb @@ -0,0 +1,49 @@ +# We monkey patch the DateTimeSelector in order to add accessibility labels +# https://stackoverflow.com/a/47836699 +module ActionView + module Helpers + class DateTimeSelector + # Given an ordering of datetime components, create the selection HTML + # and join them with their appropriate separators. + def build_selects_from_types(order) + select = "" + order.reverse_each do |type| + separator = separator(type) + select.insert(0, separator.to_s + send("select_#{type}").to_s) + end + # rubocop:disable Rails/OutputSafety + select.html_safe + # rubocop:enable Rails/OutputSafety + end + + def datetime_accessibility_label(n, label) + prefix_re = @options[:prefix].match('(.*)\[(.*)\]\[(\d+)\]') + if prefix_re.nil? || prefix_re.size < 2 + prefix = [] + else + prefix = prefix_re.to_a.drop(1) + end + field_for = "#{prefix.join('_')}_#{@options[:field_name]}" + + "" + end + + # Returns the separator for a given datetime component. + def separator(type) + return "" if @options[:use_hidden] + case type + when :year + datetime_accessibility_label(1, 'Année') + when :month + datetime_accessibility_label(2, 'Mois') + when :day + datetime_accessibility_label(3, 'Jour') + when :hour + (@options[:discard_year] && @options[:discard_day]) ? "" : @options[:datetime_separator] + datetime_accessibility_label(4, 'Heure') + when :minute, :second + @options[:"discard_#{type}"] ? "" : datetime_accessibility_label(5, 'Minute') + end + end + end + end +end diff --git a/spec/features/users/brouillon_spec.rb b/spec/features/users/brouillon_spec.rb index 3acd1adc2..42bd5ec3c 100644 --- a/spec/features/users/brouillon_spec.rb +++ b/spec/features/users/brouillon_spec.rb @@ -19,7 +19,7 @@ feature 'The user' do fill_in('text', with: 'super texte') fill_in('textarea', with: 'super textarea') fill_in('date', with: '12-12-2012') - select_date_and_time(Time.zone.parse('06/01/1985 7h05'), form_id_for('datetime')) + select_date_and_time(Time.zone.parse('06/01/1985 7h05'), form_id_for_datetime('datetime')) fill_in('number', with: '42') check('checkbox') choose('Madame') @@ -74,7 +74,7 @@ feature 'The user' do expect(page).to have_field('text', with: 'super texte') expect(page).to have_field('textarea', with: 'super textarea') expect(page).to have_field('date', with: '2012-12-12') - check_date_and_time(Time.zone.parse('06/01/1985 7:05'), form_id_for('datetime')) + check_date_and_time(Time.zone.parse('06/01/1985 7:05'), form_id_for_datetime('datetime')) expect(page).to have_field('number', with: '42') expect(page).to have_checked_field('checkbox') expect(page).to have_checked_field('Madame') @@ -250,6 +250,32 @@ feature 'The user' do find(:xpath, ".//label[contains(text()[normalize-space()], '#{libelle}')]")[:for] end + def form_id_for_datetime(libelle) + # The HTML for datetime is a bit specific since it has 5 selects, below here is a sample HTML + # So, we want to find the partial id of a datetime (partial because there are 5 ids: + # dossier_champs_attributes_3_value_1i, 2i, ... 5i) ; we are interested in the 'dossier_champs_attributes_3_value' part + # which is then completed in select_date_and_time and check_date_and_time + # + # We find the H2, find the first select in the next .datetime div, then strip the last 3 characters + # + #

+ # libelle + #

+ #
+ # + # + # + #
+ e = find(:xpath, ".//h4[contains(text()[normalize-space()], '#{libelle}')]") + e.sibling('.datetime').first('select')[:id][0..-4] + end + def champ_value_for(libelle) champs = user_dossier.champs champs.find { |c| c.libelle == libelle }.value