View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
20283 | Bug reports | Accessibility | public | 2025-10-03 15:30 | 2025-10-03 16:04 |
Reporter | dan24 | Assigned To | |||
Priority | none | Severity | minor | ||
Status | new | Resolution | open | ||
Summary | 20283: No focus on ranking question - no possibility to navigate with keyboard | ||||
Description | Hello, With Limesurvey V3.28.77 and it's the same with V6.14, the ranking question didn't tke the focus (vanilla theme for exemple). | ||||
Steps To Reproduce | Steps to reproduceMake a survey , with Vanilla thème, where there is question type "ranking" and try to answer it like a visually impaired person Expected resultwith the tab key il should be able to select and validate my choice Actual resultNo focus, no keyboard navigation | ||||
Tags | No tags attached. | ||||
Bug heat | 6 | ||||
Complete LimeSurvey version number (& build) | V6.14 | ||||
I will donate to the project if issue is resolved | No | ||||
Browser | firefox | ||||
Database type & version | Mariadb | ||||
Server OS (if known) | |||||
Webserver software & version (if known) | nginx | ||||
PHP Version | 7.4 | ||||
Not only focus (adding tabindex didn't fix the issue) |
|
Not really true : blind people have the dropdown. But yes, inaccessible for a lot of user. See https://gitlab.com/SondagesPro/QuestionTheme/rankingDropDown for an alternative (dropdown for all) |
|
In V3.28.77 we are doing some modifications for a keyboard navigation, and we report it in the V6.14
RenderRanking.php (7,152 bytes)
<?php /** * RenderClass for Boilerplate Question * * The ia Array contains the following * 0 => string qid * 1 => string sgqa * 2 => string questioncode * 3 => string question * 4 => string type * 5 => string gid * 6 => string mandatory, * 7 => string conditionsexist, * 8 => string usedinconditions * 0 => string used in group.php for question count * 10 => string new group id for question in randomization group (GroupbyGroup Mode) * */ class RenderRanking extends QuestionBaseRenderer { private $inputnames = []; private $aDisplayAnswers = []; private $iMaxSubquestions; private $mMaxAnswers; private $mMinAnswers; private $sLabeltext; public function __construct($aFieldArray, $bRenderDirect = false) { parent::__construct($aFieldArray, $bRenderDirect); $this->setAnsweroptions(); $this->iMaxSubquestions = ((int) $this->getQuestionAttribute('max_subquestions')) > 0 ? ((int) $this->getQuestionAttribute('max_subquestions')) : $this->getAnswerCount(); $this->mMaxAnswers = trim((string) $this->getQuestionAttribute('max_answers')) != '' ? ( ($this->iMaxSubquestions < $this->getAnswerCount()) ? "min(" . trim((string) $this->getQuestionAttribute('max_answers')) . "," . $this->iMaxSubquestions . ")" : trim((string) $this->getQuestionAttribute('max_answers')) ) : $this->iMaxSubquestions; $this->mMinAnswers = $this->setDefaultIfEmpty($this->getQuestionAttribute('min_answers'), 0); } public function getMainView() { return '/survey/questions/answer/ranking'; } public function getRows() { // Get the max number of line needed $iMaxLine = ( (ctype_digit((string) $this->mMaxAnswers) && intval($this->mMaxAnswers) < $this->iMaxSubquestions) ? $this->mMaxAnswers : $this->iMaxSubquestions ); $sSelects = ''; $curValue = ''; for ($i = 1; $i <= $iMaxLine; $i++) { $myfname = $this->sSGQA . $i; $this->sLabeltext = ($i == 1) ? gT('First choice') : sprintf(gT('Choice of rank %s'), $i); aItemData = []; if (!$_SESSION['survey_' . Yii::app()->getConfig('surveyID')][$myfname]) { $aItemData[] = array( 'value' => '', 'selected' => 'SELECTED', 'classes' => '', 'id' => '', 'optiontext' => gT('Please choose...'), ); } foreach ($this->aAnswerOptions[0] as $oAnswer) { $this->aDisplayAnswers[$oAnswer->aid] = array_merge($oAnswer->attributes, $oAnswer->answerl10ns[$this->sLanguage]->attributes); $mSessionValue = $this->setDefaultIfEmpty($_SESSION['survey_' . Yii::app()->getConfig('surveyID')][$myfname], false); if ($mSessionValue == $oAnswer->code) { $selected = SELECTED; $curValue = $mSessionValue; } else { $selected = ''; } $aItemData[] = array( 'value' => $oAnswer->code, 'selected' => $selected, 'classes' => '', 'optiontext' => $oAnswer->answerl10ns[$this->sLanguage]->answer ); } //Redbug PNEWEB 9627 ajout code en cours et passage de variable dans doRender qui suit $j = $i-1; $codeEnCours = $itemDatas[$i]['value']; $sSelects .= Yii::app()->twigRenderer->renderQuestion( $this->getMainView() . '/rows/answer_row', array( 'myfname' => $myfname, 'labeltext' => $this->sLabeltext, 'options' => $aItemData, 'thisvalue' => $curValue, 'answers' => $answers, 'rankingName' => $ia[1], 'codeEnCours' => $codeEnCours ), true ); $inputnames[] = $myfname } return $sSelects; } public function render($sCoreClasses = '') { $answer = ''; $sCoreClasses = "ls-answers answers-lists select-sortable-lists " . $sCoreClasses; if (!empty($this->getQuestionAttribute('time_limit'))) { $answer .= $this->getTimeSettingRender(); } $rankingTranslation = 'LSvar.lang.rankhelp="' . gT("Double-click or drag-and-drop items in the left list to move them to the right - your highest ranking item should be on the top right, moving through to your lowest ranking item.", 'js') . ' Sans souris, Shift + r remplace le double-click sur l\'élément ayant le focus.'. '";'; $rankingTranslation .= 'LSvar.lang.rankadvancedhelp="' . gT("Drag or double-click images into order.", 'js') . '";'; $this->addScript("rankingTranslation", $rankingTranslation, CClientScript::POS_BEGIN); //$this->applyScripts(); if (trim((string) $this->getQuestionAttribute('choice_title', App()->language)) != '') { $choice_title = htmlspecialchars(trim((string) $this->getQuestionAttribute('choice_title', App()->language)), ENT_QUOTES); } else { $choice_title = gT("Available items", 'html'); } if (trim((string) $this->getQuestionAttribute('rank_title', App()->language)) != '') { $rank_title = htmlspecialchars(trim((string) $this->getQuestionAttribute('rank_title', App()->language)), ENT_QUOTES); } else { $rank_title = gT("Your ranking", 'html'); } $answer .= Yii::app()->twigRenderer->renderQuestion($this->getMainView() . '/answer', array( 'coreClass' => $sCoreClasses, 'sSelects' => $this->getRows(), 'thisvalue' => $this->mSessionValue, 'answers' => $this->aDisplayAnswers, 'myfname' => $this->sSGQA, 'labeltext' => $this->sLabeltext, 'qId' => $this->oQuestion->qid, 'rankingName' => $this->sSGQA, 'basename' => $this->sSGQA, 'max_answers' => $this->mMaxAnswers, 'min_answers' => $this->mMinAnswers, 'choice_title' => $choice_title, 'rank_title' => $rank_title, 'showpopups' => $this->getQuestionAttribute("showpopups"), 'samechoiceheight' => $this->getQuestionAttribute("samechoiceheight"), ), true); $this->registerAssets(); $inputnames[] = $this->sSGQA; return array($answer, $this->inputnames); } } 'samelistheight' => $this->getQuestionAttribute("samelistheight"), answer_row.twig (1,117 bytes)
{# <?php /** * Ranking question, item Html * @var $value * @var $selected * @var $classes * @var $id * @var $optiontext */ ?> #} <!-- Redbug 9627 ajout de javascript pour activer le focus --> <li class="select-item mb-3"> <label for="answer{{myfname}}" class="control-label col-md-4"> {{ processString(labeltext) }} </label> <div class="col-md-8"> <select tabindex="0" class='form-select' name="{{myfname}}" id="answer{{myfname}}"> {% for option in options %} <option value="{{ option.value }}" {{ option.selected }} class='{{option.classes}}'> {{ flatString(processString(option.optiontext,1)) }} </option> {% endfor %} </select> <!-- Hidden form: maybe can be replaced with ranking.js --> <input type="hidden" id="java{{myfname}}" disabled="disabled" value="{{thisvalue}}"/> </div> </li> <script> document.addEventListener("DOMContentLoaded", function() { setFocus("answer{{myfname}}","javatbd{{rankingName}}{{codeEnCours}}"); }); </script> answer.twig (5,515 bytes)
{# !!!! BECAREFUL: ONLY FOR TESTING !!!!! !!!! DON'T START TO TRANSLATE ALL VIEWS BASED ON THIS MODEL !!!!! !!!! IT WILL PROBABLY FIRST NEED TO CHANGE THE TWIG TEMPLATE SYNTAX TO AVOID CONFLICT WITH EXPRESSION MANAGER !!!! /** * Ranking question, item list header Html * * @var $sOptions : the select options, generated with the view answer_row.php * * @var $name * @var $myfname * @var $labeltext * @var $rankId * @var $rankingName * @var $max_answers * @var $min_answers * @var $qid * @var $choice_title * @var $rank_title * @var $rank_help * @var $showpopups * @var $samechoiceheight * @var $samelistheight **** Additional attributes: * @var question_template_attribute.show_handle * @var question_template_attribute.only_pull * @var question_template_attribute.visualize */ #} <!-- Redbug 9627 ajout de javascript pour simuler le double click via les touches shift + r et la prise de focus tabindex --> <script> function setFocus(inputId, targetId) { const inputElement = document.getElementById(inputId); const targetElement = document.getElementById(targetId); inputElement.addEventListener('focus', () => { targetElement.focus(); }); } </script> <!-- answer --> <div class="{{coreClass}}"> <ul class="list-unstyled ls-js-hidden-sr answers-list select-list " role="group" aria-labelledby="ls-question-text-{{basename}}"> {# rows/answer_row.twig #} {{sSelects}} </ul> <div class="ls-no-js-hidden answers-list{{ samechoiceheight ? " list-samechoiceheight": "" }} {{ samelistheight ? " list-samelistheight": "" }} row" aria-hidden="true"> <div class="col-md-6 col-6 ranking-available-items"> <strong class="sortable-subtitle sortable-rank-subtitle">{{choice_title}}</strong> <ul id="sortable-choice-{{qId}}" class="sortable-choice sortable-list list-group"> {% for ansrow in answers %} <li id="javatbd{{rankingName}}{{ansrow.code}}" tabindex="0" class="ls-choice list-group-item answer-item sortable-item grabable sortable-enable" data-value="{{ansrow.code}}"> {{ processString(ansrow.answer) }} <span class="grabable selector__dragHandle d-none float-end"> <svg class="" width="9" height="14" viewBox="0 0 9 14" fill="none" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" clip-rule="evenodd" d="M0.4646 0.125H3.24762V2.625H0.4646V0.125ZM6.03064 0.125H8.81366V2.625H6.03064V0.125ZM0.4646 5.75H3.24762V8.25H0.4646V5.75ZM6.03064 5.75H8.81366V8.25H6.03064V5.75ZM0.4646 11.375H3.24762V13.875H0.4646V11.375ZM6.03064 11.375H8.81366V13.875H6.03064V11.375Z" fill="currentColor"/> </svg> </span> </li> <script> document.getElementById("javatbd{{rankingName}}{{ansrow.code}}").addEventListener('keydown', function(event) { // Vérifier si les touches shift et r sont pressées if (event.shiftKey && event.key === "R") { let focusedElement = document.activeElement; if (focusedElement) { let dblclickEvent = new MouseEvent("dblclick", { bubbles: true, cancelable: true, view: window }); focusedElement.dispatchEvent(dblclickEvent); } } }); </script> {% endfor %} <li class="d-none ls-remove"></li> </ul> </div> <div class="col-md-6 col-6 ranking-sorted-items"> <strong class="sortable-subtitle sortable-rank-subtitle">{{rank_title}}</strong> <ul id="sortable-rank-{{qId}}" class="sortable-rank sortable-list list-group"> <li class="d-none ls-remove"></li> </ul> </div> </div> </div> {% set script %} try{ var ranking{{qId}} = new RankingQuestion({ max_answers : "{{ processString("{" ~ max_answers ~ "}", 1) }}", min_answers : "{{ processString("{" ~ min_answers ~ "}", 1) }}", showpopups : "{{showpopups}}", samechoiceheight : "{{samechoiceheight}}", samelistheight : "{{samelistheight}}", rankingName : "{{rankingName}}", questionId : "{{qId}}" }); ranking{{qId}}.init() } catch(e){} {% endset %} {{ registerPackage('sortablejs') }} {{ registerPackage('question-ranking') }} {{ registerScript( 'RankingQuestionTranslate'~qId, 'LSvar.lang.rankhelp="' ~ gT("Double-click or drag-and-drop items in the left list to move them to the right - your highest ranking item should be on the top right, moving through to your lowest ranking item.") ~ '";', 'POS_BEGIN') }} {{ registerScript( 'RankingQuestion'~qId, script, 'POS_POSTSCRIPT') }} <!-- end of answer --> <!-- @todo : move htmlblock at the good place --> |
|
Ok thank you for : I replace Ranking question by it for accessibility audit thanks |
|
Date Modified | Username | Field | Change |
---|---|---|---|
2025-10-03 15:30 | dan24 | New Issue | |
2025-10-03 15:40 | DenisChenu | Note Added: 83528 | |
2025-10-03 15:40 | DenisChenu | Bug heat | 0 => 2 |
2025-10-03 15:40 | DenisChenu | Issue Monitored: DenisChenu | |
2025-10-03 15:40 | DenisChenu | Bug heat | 2 => 4 |
2025-10-03 15:44 | DenisChenu | Note Added: 83529 | |
2025-10-03 15:51 | dan24 | Note Added: 83530 | |
2025-10-03 15:51 | dan24 | File Added: RenderRanking.php | |
2025-10-03 15:51 | dan24 | File Added: answer_row.twig | |
2025-10-03 15:51 | dan24 | File Added: answer.twig | |
2025-10-03 15:51 | dan24 | Bug heat | 4 => 6 |
2025-10-03 16:04 | dan24 | Note Added: 83531 |