Skip to content

Commit

Permalink
MDL-64464 drag-drop qtypes: allow <span lang=".."> id draggables
Browse files Browse the repository at this point in the history
This is for accessibility, so that screen readers can read the drag
items with correct pronunciation.
  • Loading branch information
timhunt committed Jan 11, 2019
1 parent 609b020 commit 6f60c7a
Show file tree
Hide file tree
Showing 10 changed files with 423 additions and 9 deletions.
4 changes: 2 additions & 2 deletions question/type/ddimageortext/edit_ddimageortext_form.php
Expand Up @@ -270,8 +270,8 @@ public function validation($data, $files) {
for ($dragindex = 0; $dragindex < $data['noitems']; $dragindex++) {
$label = $data['draglabel'][$dragindex];
if ($data['drags'][$dragindex]['dragitemtype'] == 'word') {
$allowedtags = '<br><sub><sup><b><i><strong><em>';
$errormessage = get_string('formerror_disallowedtags', 'qtype_ddimageortext');
$allowedtags = '<br><sub><sup><b><i><strong><em><span>';
$errormessage = get_string('formerror_disallowedtags', 'qtype_ddimageortext', s($allowedtags));
} else {
$allowedtags = '';
$errormessage = get_string('formerror_noallowedtags', 'qtype_ddimageortext');
Expand Down
Expand Up @@ -37,7 +37,7 @@
$string['dropbackground'] = 'Background image for dragging markers onto';
$string['dropzone'] = 'Drop zone {$a}';
$string['dropzoneheader'] = 'Drop zones';
$string['formerror_disallowedtags'] = 'Sorry, HTML tags are not allowed in draggable text.';
$string['formerror_disallowedtags'] = 'Only "{$a}" tags are allowed in this draggable text.';
$string['formerror_noallowedtags'] = 'HTML tags are not allowed in this text which is the alt text for a draggable image.';
$string['formerror_noytop'] = 'You must provide a value for the y coordinate for the top left corner of this drop area. You can drag and drop the drop area above to set the coordinates or enter them manually here.';
$string['formerror_noxleft'] = 'You must provide a value for the x coordinate for the top left corner of this drop area. You can drag and drop the drop area above to set the coordinates or enter them manually here.';
Expand Down
108 changes: 108 additions & 0 deletions question/type/ddimageortext/tests/edit_form_test.php
@@ -0,0 +1,108 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Unit tests for the drag-and-drop onto image edit form.
*
* @package qtype_ddimageortext
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();
global $CFG;

require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
require_once($CFG->dirroot . '/question/type/edit_question_form.php');
require_once($CFG->dirroot . '/question/type/ddimageortext/edit_ddimageortext_form.php');

/**
* Unit tests for the drag-and-drop onto image edit form.
*
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_ddimageortext_edit_form_test extends advanced_testcase {
/**
* Helper method.
*
* @return array with two elements:
* question_edit_form great a question form instance that can be tested.
* stdClass the question category.
*/
protected function get_form() {
$this->setAdminUser();
$this->resetAfterTest();

$syscontext = context_system::instance();
$category = question_make_default_categories(array($syscontext));
$fakequestion = new stdClass();
$fakequestion->qtype = 'ddimageortext';
$fakequestion->contextid = $syscontext->id;
$fakequestion->createdby = 2;
$fakequestion->category = $category->id;
$fakequestion->questiontext = 'Test question';
$fakequestion->options = new stdClass();
$fakequestion->options->answers = array();
$fakequestion->formoptions = new stdClass();
$fakequestion->formoptions->movecontext = null;
$fakequestion->formoptions->repeatelements = true;
$fakequestion->inputs = null;

$form = new qtype_ddimageortext_edit_form(new moodle_url('/'), $fakequestion, $category,
new question_edit_contexts($syscontext));

return [$form, $category];
}

/**
* Test the form correctly validates the HTML allowed in items.
*/
public function test_item_validation() {
list($form, $category) = $this->get_form();

$submitteddata = [
'category' => $category->id,
'bgimage' => '',
'nodropzone' => 0,
'noitems' => 5,
'drags' => [
['dragitemtype' => 'image'],
['dragitemtype' => 'image'],
['dragitemtype' => 'word'],
['dragitemtype' => 'word'],
['dragitemtype' => 'word'],
],
'draglabel' => [
'frog',
'<b>toad</b>',
'cat',
'<span lang="fr"><b>chien</b></span>',
'<textarea>evil!</textarea>',
],
];

$errors = $form->validation($submitteddata, []);

$this->assertArrayNotHasKey('drags[0]', $errors);
$this->assertEquals('HTML tags are not allowed in this text which is the alt text for a draggable image.',
$errors['drags[1]']);
$this->assertArrayNotHasKey('drags[2]', $errors);
$this->assertArrayNotHasKey('drags[3]', $errors);
$this->assertEquals('Only "&lt;br&gt;&lt;sub&gt;&lt;sup&gt;&lt;b&gt;&lt;i&gt;&lt;strong&gt;&lt;em&gt;&lt;span&gt;" ' .
'tags are allowed in this draggable text.', $errors['drags[4]']);
}
}
37 changes: 36 additions & 1 deletion question/type/ddimageortext/tests/helper.php
Expand Up @@ -34,7 +34,7 @@
*/
class qtype_ddimageortext_test_helper extends question_test_helper {
public function get_test_questions() {
return array('fox', 'maths', 'xsection');
return array('fox', 'maths', 'xsection', 'mixedlang');
}

/**
Expand Down Expand Up @@ -248,4 +248,39 @@ public function get_ddimageortext_question_form_data_xsection() {

return $fromform;
}

/**
* Make a test question where the drag items are a different language than the main question text.
*
* @return qtype_ddimageortext_question
*/
public function make_ddimageortext_question_mixedlang() {
question_bank::load_question_definition_classes('ddimageortext');
$dd = new qtype_ddimageortext_question();

test_question_maker::initialise_a_question($dd);

$dd->name = 'Question about French in English.';
$dd->questiontext = '<p>Complete the blanks in this sentence.</p>' .
'<p lang="fr">J\'ai perdu [[1]] plume de [[2]] tante - l\'avez-vous vue?</p>';
$dd->generalfeedback = 'This sentence uses each letter of the alphabet.';
$dd->qtype = question_bank::get_qtype('ddimageortext');

$dd->shufflechoices = true;

test_question_maker::set_standard_combined_feedback_fields($dd);

$dd->choices = $this->make_choice_structure(array(
new qtype_ddimageortext_drag_item('<span lang="fr">la</span>', 1, 1),
new qtype_ddimageortext_drag_item('<span lang="fr">ma</span>', 2, 1),
));

$dd->places = $this->make_place_structure(array(
new qtype_ddimageortext_drop_zone('', 1, 1),
new qtype_ddimageortext_drop_zone('', 2, 1)
));
$dd->rightchoices = array(1 => 1, 2 => 2);

return $dd;
}
}
16 changes: 16 additions & 0 deletions question/type/ddimageortext/tests/walkthrough_test.php
Expand Up @@ -855,4 +855,20 @@ public function test_display_of_right_answer_when_shuffled() {
$this->check_current_state(question_state::$gradedright);
$this->check_current_mark(3);
}

public function test_mixed_lang_rendering() {

// Create a mixe drag-and-drop question.
$dd = test_question_maker::make_question('ddimageortext', 'mixedlang');
$dd->shufflechoices = false;
$this->start_attempt_at_question($dd, 'interactive', 1);

// Check the initial state.
$this->check_current_state(question_state::$todo);
$this->check_current_mark(null);
$this->check_current_output(
new question_pattern_expectation('~<div class="group1 draghome dragitemhomes1 choice1 yui3-cssfonts"><span lang="fr">la</span></div>~'),
new question_pattern_expectation('~<div class="group1 draghome dragitemhomes2 choice2 yui3-cssfonts"><span lang="fr">ma</span></div>~')
);
}
}
2 changes: 1 addition & 1 deletion question/type/ddmarker/edit_ddmarker_form.php
Expand Up @@ -29,7 +29,7 @@
require_once($CFG->dirroot.'/question/type/ddimageortext/edit_ddtoimage_form_base.php');
require_once($CFG->dirroot.'/question/type/ddmarker/shapes.php');

define('QTYPE_DDMARKER_ALLOWED_TAGS_IN_MARKER', '<br><i><em><b><strong><sup><sub><u>');
define('QTYPE_DDMARKER_ALLOWED_TAGS_IN_MARKER', '<br><i><em><b><strong><sup><sub><u><span>');


/**
Expand Down
99 changes: 99 additions & 0 deletions question/type/ddmarker/tests/edit_form_test.php
@@ -0,0 +1,99 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Unit tests for the drag-and-drop markers edit form.
*
* @package qtype_ddmarker
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

defined('MOODLE_INTERNAL') || die();
global $CFG;

require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
require_once($CFG->dirroot . '/question/type/edit_question_form.php');
require_once($CFG->dirroot . '/question/type/ddmarker/edit_ddmarker_form.php');

/**
* Unit tests for the drag-and-drop markers edit form.
*
* @copyright 2019 The Open University
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_ddmarker_edit_form_test extends advanced_testcase {
/**
* Helper method.
*
* @return array with two elements:
* question_edit_form great a question form instance that can be tested.
* stdClass the question category.
*/
protected function get_form() {
$this->setAdminUser();
$this->resetAfterTest();

$syscontext = context_system::instance();
$category = question_make_default_categories(array($syscontext));
$fakequestion = new stdClass();
$fakequestion->qtype = 'ddmarker';
$fakequestion->contextid = $syscontext->id;
$fakequestion->createdby = 2;
$fakequestion->category = $category->id;
$fakequestion->questiontext = 'Test question';
$fakequestion->options = new stdClass();
$fakequestion->options->answers = array();
$fakequestion->formoptions = new stdClass();
$fakequestion->formoptions->movecontext = null;
$fakequestion->formoptions->repeatelements = true;
$fakequestion->inputs = null;

$form = new qtype_ddmarker_edit_form(new moodle_url('/'), $fakequestion, $category,
new question_edit_contexts($syscontext));

return [$form, $category];
}

/**
* Test the form correctly validates the HTML allowed in items.
*/
public function test_item_validation() {
list($form, $category) = $this->get_form();

$submitteddata = [
'category' => $category->id,
'bgimage' => 0,
'nodropzone' => 0,
'noitems' => 4,
'drags' => [
['label' => 'frog'],
['label' => '<b>toad</b>'],
['label' => '<span lang="fr"><em>chien</em></span>'],
['label' => '<textarea>evil!</textarea>'],
],
];

$errors = $form->validation($submitteddata, []);

$this->assertArrayNotHasKey('drags[0]', $errors);
$this->assertArrayNotHasKey('drags[1]', $errors);
$this->assertArrayNotHasKey('drags[2]', $errors);
$this->assertEquals('Only "&lt;br&gt;&lt;i&gt;&lt;em&gt;&lt;b&gt;&lt;strong&gt;' .
'&lt;sup&gt;&lt;sub&gt;&lt;u&gt;&lt;span&gt;" tags are allowed in the label for a marker.',
$errors['drags[3]']);
}
}

0 comments on commit 6f60c7a

Please sign in to comment.