From 04f57f896fc5d508253f6335b3766410894f3191 Mon Sep 17 00:00:00 2001 From: Jaimos Skriletz Date: Sat, 8 Aug 2026 18:31:04 -0600 Subject: [PATCH] Add aria labels to PGML and unify their use. Update the `generate_aria_label` method to be given an input label. If the input label is defined and doesn't contain `%s`, return the label. If the input label is undefined (or blank) generate a default label based on the problem number, answer number, and part number. If the input label contains `%s`, replace it with the default generated label and return the result. Update answer rules to more uniformly accept the `aria_label` option and use the `generate_aria_label` method. This required updating some and adding the option to others. Update macros that use the `generate_aria_label` method to take advantage of the new method. The parserRadioButtons and parserCheckboxList will append "option X" to the end of the generated label. Matrix arrays will append "col N row M" to the end of the generated label. Update PGML to accept the `aria_label` option in answer blanks to customize the label, "[_]{$answer}{aria_label => '%s label'}". The biggest change was in parserRadioMultiAnswer which allows a new option `ariaLabels` which is the labels to send to the associated answer rules. Update its internal `generate_aria_label` function to match the changes to the one in PGbasicmacros. In addition the "subpart X" is only added to the label if there are more than one subparts, and the "part Y" will use the label of the part if `displayLabels` is set, otherwise it uses the number of the part. --- lib/Value/AnswerChecker.pm | 14 ++-- macros/core/PGML.pl | 17 +++-- macros/core/PGbasicmacros.pl | 88 +++++++++++++----------- macros/core/PGessaymacros.pl | 2 +- macros/parsers/parserCheckboxList.pl | 2 +- macros/parsers/parserMultiAnswer.pl | 23 +++---- macros/parsers/parserPopUp.pl | 6 +- macros/parsers/parserRadioButtons.pl | 21 +++--- macros/parsers/parserRadioMultiAnswer.pl | 63 +++++++++++------ macros/parsers/parserWordCompletion.pl | 2 +- 10 files changed, 132 insertions(+), 106 deletions(-) diff --git a/lib/Value/AnswerChecker.pm b/lib/Value/AnswerChecker.pm index bc2b157196..34d1ff3723 100644 --- a/lib/Value/AnswerChecker.pm +++ b/lib/Value/AnswerChecker.pm @@ -441,21 +441,17 @@ sub ans_matrix { my $named_ans_rule = pgRef('NAMED_ANS_RULE'); my $HTML = ""; pgCall('RECORD_IMPLICIT_ANS_NAME', $name = pgCall('NEW_ANS_NAME')) unless $name; - my $ename = "${answerPrefix}_${name}"; + my $ename = "${answerPrefix}_${name}"; + my $base_label = pgCall('generate_aria_label', $ename, $options{aria_label}); $self->{ans_name} = $ename; $self->{ans_rows} = $rows; $self->{ans_cols} = $cols; # warn "ans_matrix: ename=$ename answer_group_name=$options{answer_group_name}"; my @array = (); - foreach my $i (0 .. $rows - 1) { + for my $i (0 .. $rows - 1) { my @row = (); - foreach my $j (0 .. $cols - 1) { - my $label; - if ($options{aria_label}) { - $label = $options{aria_label} . pgCall('maketext', 'row [_1] col [_2] ', $i + 1, $j + 1); - } else { - $label = pgCall('generate_aria_label', ANS_NAME($ename, $i, $j)); - } + for my $j (0 .. $cols - 1) { + my $label = $base_label . pgCall('maketext', 'row [_1] col [_2] ', $i + 1, $j + 1); my $answer_group_name = $options{answer_group_name} // $name; if ($i == 0 && $j == 0) { if ($extend) { diff --git a/macros/core/PGML.pl b/macros/core/PGML.pl index 9fe50219d5..4d9abc9275 100644 --- a/macros/core/PGML.pl +++ b/macros/core/PGML.pl @@ -404,7 +404,7 @@ sub Image { sub Answer { my $self = shift; my $token = shift; - my $def = { options => [ "answer", "width", "name", "cmp_options" ] }; + my $def = { options => [ 'answer', 'width', 'name', 'cmp_options', 'aria_label' ] }; $def->{hasStar} = 1 if $token =~ m/\*$/; $self->Item("answer", $token, $def); } @@ -1285,6 +1285,11 @@ sub string { return join('', @strings); } +sub aria_label { + my ($self, $label) = @_; + return $label ? (aria_label => "$label ") : (); +} + sub nl { my $self = shift; my $nl = $self->{nl}; @@ -1373,10 +1378,10 @@ sub Answer { if (defined($ans)) { if (ref($ans) eq 'CODE' || (ref($ans) eq 'AnswerEvaluator' && !Value::isValue($ans->{rh_ans}{correct_value}))) { if (defined($item->{name})) { - $rule = main::NAMED_ANS_RULE($item->{name}, $item->{width}); + $rule = main::NAMED_ANS_RULE($item->{name}, $item->{width}, $self->aria_label($item->{aria_label})); main::NAMED_ANS($item->{name} => $ans); } else { - $rule = main::ans_rule($item->{width}); + $rule = main::ans_rule($item->{width}, $self->aria_label($item->{aria_label})); main::ANS($ans); } } else { @@ -1398,7 +1403,7 @@ sub Answer { $ans = main::String(""); ### use something else? } } - my @options = ($item->{width}); + my @options = ($item->{width}, $self->aria_label($item->{aria_label})); my $method = ($item->{hasStar} ? "ans_array" : "ans_rule"); if ($item->{name}) { unshift(@options, $item->{name}); @@ -1426,9 +1431,9 @@ sub Answer { } } else { if (defined($item->{name})) { - $rule = main::NAMED_ANS_RULE($item->{name}, $item->{width}); + $rule = main::NAMED_ANS_RULE($item->{name}, $item->{width}, $self->aria_label($item->{aria_label})); } else { - $rule = main::ans_rule($item->{width}); + $rule = main::ans_rule($item->{width}, $self->aria_label($item->{aria_label})); } } return $rule; diff --git a/macros/core/PGbasicmacros.pl b/macros/core/PGbasicmacros.pl index 2b204e7f41..2198d250c5 100644 --- a/macros/core/PGbasicmacros.pl +++ b/macros/core/PGbasicmacros.pl @@ -309,7 +309,7 @@ sub NAMED_ANS_RULE { size => $col, name => $name, id => $name, - aria_label => $options{aria_label} // generate_aria_label($name), + aria_label => generate_aria_label($name, $options{aria_label}), dir => 'auto', autocomplete => 'off', autocapitalize => 'off', @@ -385,7 +385,7 @@ sub NAMED_ANS_RULE_EXTENSION { size => $col, name => $name, id => $name, - aria_label => $options{aria_label} // generate_aria_label($name), + aria_label => generate_aria_label($name, $options{aria_label}), dir => 'auto', autocomplete => 'off', autocapitalize => 'off', @@ -402,7 +402,7 @@ sub ANS_RULE { my ($number, $col) = @_; my $name = NEW_ANS_NAME(); RECORD_IMPLICIT_ANS_NAME($name); - return NAMED_ANS_RULE($name, $col); + return NAMED_ANS_RULE($name, $col, @_); } sub NAMED_ANS_BOX { @@ -413,7 +413,6 @@ sub NAMED_ANS_BOX { my $height = .07 * $row; my $answer_value = $inputs_ref->{$name} // ''; $name = RECORD_ANS_NAME($name, $answer_value); - my $label = $options{aria_label} // generate_aria_label($name); return MODES( TeX => qq!\\vskip $height in \\hrulefill\\quad !, @@ -426,7 +425,7 @@ sub NAMED_ANS_BOX { id => $name, rows => $row, cols => $col, - aria_label => $label, + aria_label => generate_aria_label($name, $options{aria_label}), encode_pg_and_html($answer_value) ) ) @@ -454,10 +453,11 @@ sub NAMED_ANS_RADIO { 'label', tag( 'input', - type => 'radio', - name => $name, - id => $name, - value => $value, + type => 'radio', + name => $name, + id => $name, + value => $value, + aria_label => generate_aria_label($name, $options{aria_label}), $checked ? (checked => undef) : (), %{ $options{attributes} } ) @@ -485,10 +485,11 @@ sub NAMED_ANS_RADIO_EXTENSION { 'label', tag( 'input', - type => 'radio', - name => $name, - id => $options{id} // "${name}_$value", - value => $value, + type => 'radio', + name => $name, + id => $options{id} // "${name}_$value", + value => $value, + aria_label => generate_aria_label($name, $options{aria_label}), $checked ? (checked => undef) : (), %{ $options{attributes} } ) @@ -508,51 +509,56 @@ sub NAMED_ANS_RADIO_BUTTONS { while (@buttons) { $value = shift @buttons; $tag = shift @buttons; - push(@out, NAMED_ANS_RADIO_EXTENSION($name, $value, $tag, aria_label => $label . "option $count ")); + push(@out, + NAMED_ANS_RADIO_EXTENSION($name, $value, $tag, aria_label => $label . maketext('option [_1] ', $count)) + ); $count++; } return wantarray ? @out : join(" ", @out); } ############################################## -# generate_aria_label( $name ) -# takes the name of an ANS_RULE and generates an appropriate -# aria label for screen readers +# generate_aria_label($name, $inLabel) +# Takes the name of an ANS_RULE and generates an appropriate aria label for screen readers. ############################################## sub generate_aria_label { - my $name = shift; - my $label = ''; + my ($name, $inLabel) = @_; + my $outLabel = ''; - # if we dont have an AnSwEr type name then we do the best we can + # Return the input label unless it contains '%s'. + if ($inLabel) { + if ($inLabel =~ /^\S$/) { + $inLabel = ''; + } else { + $inLabel = "$inLabel " unless $inLabel =~ / $/; + return $inLabel unless $inLabel =~ /%s/; + } + } + + # If we don't have an AnSwEr type name then we do the best we can. if ($name !~ /AnSwEr\d+/) { - return maketext('answer [_1] ', $name); + $outLabel = maketext('answer [_1] ', $name); + return $inLabel ? $inLabel =~ s/%s/$outLabel/r : $outLabel; } - # check for quiz prefix + # Check for quiz prefix. if ($name =~ /^Q\d+/ || $name =~ /^MaTrIx_Q\d+/) { $name =~ s/Q0*(\d+)_//; - $label .= maketext('problem [_1] ', $1); + $outLabel .= maketext('problem [_1] ', $1); } - # get answer number + # Get answer number. $name =~ /AnSwEr0*(\d+)/; - $label .= maketext('answer [_1] ', $1); + $outLabel .= maketext('answer [_1] ', $1); - # check for Multianswer + # Check for Multianswer. if ($name =~ /MuLtIaNsWeR_/) { - $name =~ s/MuLtIaNsWeR_//; $name =~ /AnSwEr(\d+)_(\d+)/; - $label .= maketext('part [_1] ', $2 + 1); + $outLabel .= maketext('part [_1] ', $2 + 1); } - # check for Matrix - if ($name =~ /^MaTrIx_/) { - $name =~ /_(\d+)_(\d+)$/; - $label .= maketext('row [_1] column [_2] ', $1 + 1, $2 + 1); - } - - return $label; + return $inLabel ? $inLabel =~ s/%s/$outLabel/r : $outLabel; } ############################################## @@ -609,7 +615,7 @@ sub NAMED_ANS_CHECKBOX { type => 'checkbox', name => $name, id => $name, - aria_label => $options{aria_label} // (generate_aria_label($name) . maketext('option [_1] ', 1)), + aria_label => generate_aria_label($name, $options{aria_label}), value => $value, $checked ? (checked => undef) : (), %{ $options{attributes} } @@ -640,8 +646,8 @@ sub NAMED_ANS_CHECKBOX_OPTION { 'input', type => 'checkbox', name => $name, - id => $options{id} // "${name}_$value", - aria_label => $options{aria_label} // generate_aria_label($name), + id => $options{id} // "${name}_$value", + aria_label => generate_aria_label($name, $options{aria_label}), value => $value, $checked ? (checked => undef) : (), %{ $options{attributes} } @@ -675,7 +681,7 @@ sub ans_rule { my $len = shift; my $name = NEW_ANS_NAME(); RECORD_IMPLICIT_ANS_NAME($name); - return NAMED_ANS_RULE($name, $len || 20); + return NAMED_ANS_RULE($name, $len || 20, @_); } sub ans_radio_buttons { @@ -832,8 +838,6 @@ sub NAMED_ANS_ARRAY_EXTENSION { $answer_value = '' unless defined($answer_value); } - my $label = $options{aria_label} // generate_aria_label($name); - # the name of the answer evaluator controlling this collection of responses. my $answer_group_name; @@ -869,7 +873,7 @@ sub NAMED_ANS_ARRAY_EXTENSION { name => $name, id => $name, class => 'codeshard', - aria_label => $label, + aria_label => generate_aria_label($name, $options{aria_label}), autocomplete => 'off', autocapitalize => 'off', spellcheck => 'false', diff --git a/macros/core/PGessaymacros.pl b/macros/core/PGessaymacros.pl index 2dcecea5bb..7d8090b733 100644 --- a/macros/core/PGessaymacros.pl +++ b/macros/core/PGessaymacros.pl @@ -119,7 +119,7 @@ sub NAMED_ESSAY_BOX { %html_options, name => $name, id => $name, - aria_label => generate_aria_label($name), + aria_label => generate_aria_label($name, $html_options{aria_label}), rows => $row, cols => $col, class => 'latexentryfield', diff --git a/macros/parsers/parserCheckboxList.pl b/macros/parsers/parserCheckboxList.pl index 9a6c86c4ea..6af06d4fd0 100644 --- a/macros/parsers/parserCheckboxList.pl +++ b/macros/parsers/parserCheckboxList.pl @@ -541,7 +541,7 @@ sub CHECKS { my @checks; main::RECORD_IMPLICIT_ANS_NAME($name = main::NEW_ANS_NAME()) unless $name; - my $label = (delete $options{aria_label}) // main::generate_aria_label($name); + my $label = main::generate_aria_label($name, delete $options{aria_label}); for my $i (0 .. $#{ $self->{orderedChoices} }) { my $value = $self->{values}[$i]; diff --git a/macros/parsers/parserMultiAnswer.pl b/macros/parsers/parserMultiAnswer.pl index ab8c1ed3a0..a32fad0b0f 100644 --- a/macros/parsers/parserMultiAnswer.pl +++ b/macros/parsers/parserMultiAnswer.pl @@ -422,26 +422,26 @@ sub NEW_NAME { # by the settings of the MultiAnswer. # sub ans_rule { - my $self = shift; - my $size = shift || 20; + my ($self, $size, %options) = @_; + $size ||= 20; my $data = $self->{data}[ $self->{part} ]; my $name = $self->ANS_NAME($self->{part}++); if ($self->{singleResult} && $self->{part} == 1) { - my $label = main::generate_aria_label($answerPrefix . $name . "_0"); main::RECORD_IMPLICIT_ANS_NAME($name) unless $self->{namedRules}; - return $data->named_ans_rule($name, $size, @_, aria_label => $label); + return $data->named_ans_rule($name, $size, %options, + aria_label => main::generate_aria_label($answerPrefix . $name . '_0', $options{aria_label})); } if ($self->{singleResult} && $self->{part} > 1) { my $extension_ans_rule = $data->named_ans_rule_extension( $name, $size, answer_group_name => $self->{answerNames}{0}, - @_ + %options ); # warn "extension rule created: $extension_ans_rule for ", ref($data); return $extension_ans_rule; } else { main::RECORD_IMPLICIT_ANS_NAME($name) unless $self->{namedRules}; - return $data->named_ans_rule($name, $size, @_); + return $data->named_ans_rule($name, $size, %options); } } @@ -451,30 +451,29 @@ sub ans_rule { # Reset the correct_ans once the array is made # sub ans_array { - my $self = shift; - my $size = shift || 5; + my ($self, $size, %options) = @_; + $size ||= 5; my $HTML; my $data = $self->{data}[ $self->{part} ]; my $name = $self->ANS_NAME($self->{part}++); if ($self->{singleResult} && $self->{part} == 1) { - my $label = main::generate_aria_label($answerPrefix . $name . "_0"); main::RECORD_IMPLICIT_ANS_NAME($name) unless $self->{namedRules}; return $data->named_ans_array( $name, $size, answer_group_name => $self->{answerNames}{0}, - @_, aria_label => $label + %options, aria_label => main::generate_aria_label($answerPrefix . $name . '_0', $options{aria_label}) ); } if ($self->{singleResult} && $self->{part} > 1) { $HTML = $data->named_ans_array_extension( $self->NEW_NAME($name), $size, answer_group_name => $self->{answerNames}{0}, - @_ + %options ); # warn "array extension rule created: $HTML for ", ref($data); } else { main::RECORD_IMPLICIT_ANS_NAME($name) unless $self->{namedRules}; - $HTML = $data->named_ans_array($name, $size, @_); + $HTML = $data->named_ans_array($name, $size, %options); } $self->{cmp}[ $self->{part} - 1 ] = $data->cmp(@ans_defaults); return $HTML; diff --git a/macros/parsers/parserPopUp.pl b/macros/parsers/parserPopUp.pl index 5c69869ab5..7ecd14a2ac 100644 --- a/macros/parsers/parserPopUp.pl +++ b/macros/parsers/parserPopUp.pl @@ -405,7 +405,7 @@ sub MENU { my $menu = ""; main::RECORD_IMPLICIT_ANS_NAME($name = main::NEW_ANS_NAME()) unless $name; my $answer_value = (defined($main::inputs_ref->{$name}) ? $main::inputs_ref->{$name} : ''); - my $aria_label = $options{aria_label} // main::generate_aria_label($name); + my $aria_label = main::generate_aria_label($name, $options{aria_label}); if ($main::displayMode =~ m/^HTML/) { if ($self->{useHTMLSelect}) { @@ -457,8 +457,8 @@ sub MENU { data_feedback_insert_method => 'append_content', join( '', - main::tag('input', type => 'hidden', name => $name, value => $answer_value), - main::tag('span', class => 'visually-hidden', $aria_label), + main::tag('input', type => 'hidden', name => $name, value => $answer_value), + main::tag('span', class => 'visually-hidden', aria_label => $aria_label), main::tag( 'button', class => 'btn dropdown-toggle text-nowrap ', diff --git a/macros/parsers/parserRadioButtons.pl b/macros/parsers/parserRadioButtons.pl index 83551ad62e..3f40a692c8 100644 --- a/macros/parsers/parserRadioButtons.pl +++ b/macros/parsers/parserRadioButtons.pl @@ -608,17 +608,16 @@ sub Index { # Create the radio-buttons text # sub BUTTONS { - my $self = shift; - my $extend = shift; - my $name = shift; - my $size = shift; + my ($self, $extend, $name, $size, %options) = @_; my @choices = @{ $self->{orderedChoices} }; my @radio = (); main::RECORD_IMPLICIT_ANS_NAME($name = main::NEW_ANS_NAME()) unless $name; - foreach my $i (0 .. $#choices) { - my $value = $self->{values}[$i]; - my $tag = $choices[$i]; + my $label = main::generate_aria_label($name, delete $options{aria_label}); + for my $i (0 .. $#choices) { + my $value = $self->{values}[$i]; + my $tag = $choices[$i]; + my $aria_label = $label . main::maketext('option [_1] ', $i + 1); $value = "%" . $value if $i == $self->{checkedI}; $tag = $self->labelFormat($self->{labels}[$i]) . $tag if $self->{displayLabels}; if ($i > 0) { @@ -626,7 +625,8 @@ sub BUTTONS { @radio, main::NAMED_ANS_RADIO_EXTENSION( $name, $value, $tag, - id => "${name}_$i", + id => "${name}_$i", + aria_label => $aria_label, $self->{uncheckable} ? ( attributes => { @@ -635,7 +635,7 @@ sub BUTTONS { } ) : (), - @_ + %options ) ); } else { @@ -643,6 +643,7 @@ sub BUTTONS { @radio, main::NAMED_ANS_RADIO( $name, $value, $tag, $extend, + aria_label => $aria_label, $self->{uncheckable} ? ( attributes => { @@ -651,7 +652,7 @@ sub BUTTONS { } ) : (), - @_ + %options ) ); } diff --git a/macros/parsers/parserRadioMultiAnswer.pl b/macros/parsers/parserRadioMultiAnswer.pl index ae9d4b2966..1b1b73940c 100644 --- a/macros/parsers/parserRadioMultiAnswer.pl +++ b/macros/parsers/parserRadioMultiAnswer.pl @@ -227,6 +227,15 @@ =head1 OPTIONS Specifies whether labels should be displayed after the radio button and before its text. This makes the association between the choices and the label used as an answer more explicit. +=item ariaLabels (Default: ariaLabels => []) + +An array reference which is a list of accessibility labels to add to the answer blanks. The +labels match the order of the answers. If the corresponding label is undefined, the default +accessibility label is of the form "answer X part Y subpart Z" (Y is the label if C +is 1, other wise the number of the radio button, and subpart Z is only shown if there are more +than one subparts). A single C<%s> can be used to include the default accessibility label as part +of the custom accessibility label, e.g. "%s custom label". + =item checked (Default: checked => undef) The index (starting at zero) of the radio button to be checked initially. By default this is @@ -290,6 +299,7 @@ sub new { values => [], namedRules => 0, cmpOpts => undef, + ariaLabels => [], checkTypes => 1, allowBlankAnswers => 0, tex_separator => ';\,', @@ -632,36 +642,41 @@ sub label { } sub generate_aria_label { - my ($name, $radioIndex, $partIndex) = @_; - my $label = ''; + my ($self, $name, $radioIndex, $partIndex, $inLabel) = @_; + my $outLabel = ''; + + # Return the input label unless it contains '%s'. + if ($inLabel) { + if ($inLabel =~ /^\S$/) { + $inLabel = ''; + } else { + $inLabel = "$inLabel " unless $inLabel =~ / $/; + return $inLabel unless $inLabel =~ /%s/; + } + } $name =~ s/$answerPrefix//; # Check for the quiz prefix. if ($name =~ /^Q\d+/ || $name =~ /^MaTrIx_Q\d+/) { $name =~ s/Q0*(\d+)_//; - $label .= main::maketext('problem [_1] ', $1); + $outLabel .= main::maketext('problem [_1] ', $1); } # Get the answer number. + my $partLabel = $self->{displayLabels} ? $self->label($radioIndex - 1) : $radioIndex; $name =~ /AnSwEr0*(\d+)/; - $label .= main::maketext('answer [_1] ', $1); + $outLabel .= + $partIndex + ? main::maketext('answer [_1] part [_2] subpart [_3] ', $1, $partLabel, $partIndex) + : main::maketext('answer [_1] part [_2] ', $1, $partLabel); - $label .= main::maketext('part [_1] ', $radioIndex); - $label .= main::maketext('subpart [_1] ', $partIndex); - - # Check for a Matrix answer. - if ($name =~ /^MaTrIx_/) { - $name =~ /_(\d+)_(\d+)$/; - $label .= main::maketext('row [_1] column [_2] ', $1 + 1, $2 + 1); - } - - return $label; + return $inLabel ? $inLabel =~ s/%s/$outLabel/r : $outLabel; } # Produce the answer rule. sub ans_rule { - my ($self, $size, @options) = @_; + my ($self, $size, %options) = @_; $size ||= 20; my @data = @{ $self->{data} }; @@ -676,8 +691,14 @@ sub ans_rule { my @part_rules; my @part_names; my @positions = $data[$i][0] =~ /(%s\*?)/g; - for (1 .. $#{ $data[$i] }) { - my $name = $self->ANS_NAME($part++); + my $subparts = $#{ $data[$i] }; + for (1 .. $subparts) { + my $name = $self->ANS_NAME($part++); + my $aria_label = $self->generate_aria_label( + $name, $i + 1, + $subparts == 1 ? 0 : $_, + $self->{ariaLabels}[ $part - 2 ] || $options{aria_label} + ); if ($positions[ $_ - 1 ] eq '%s*') { push( @part_rules, @@ -688,8 +709,8 @@ sub ans_rule { ? (defined $size->[$i][ $_ - 1 ] ? $size->[$i][ $_ - 1 ] : 20) : $size, answer_group_name => $radio_name, - aria_label => generate_aria_label($name, $i + 1, $_), - @options + %options, + aria_label => $aria_label, ) ) ); @@ -704,8 +725,8 @@ sub ans_rule { ? (defined $size->[$i][ $_ - 1 ] ? $size->[$i][ $_ - 1 ] : 20) : $size, answer_group_name => $radio_name, - aria_label => generate_aria_label($name, $i + 1, $_), - @options + %options, + aria_label => $aria_label, ) ) ); diff --git a/macros/parsers/parserWordCompletion.pl b/macros/parsers/parserWordCompletion.pl index 53c88fdb4c..4ccac0df52 100644 --- a/macros/parsers/parserWordCompletion.pl +++ b/macros/parsers/parserWordCompletion.pl @@ -86,7 +86,7 @@ sub menu { name => $name, id => $name, list => "$name-list", - aria_label => $options{aria_label} // main::generate_aria_label($name), + aria_label => main::generate_aria_label($name, $options{aria_label}), dir => 'auto', autocomplete => 'off', autocapitalize => 'off',