Skip to content
Merged
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
15 changes: 12 additions & 3 deletions question.php
Original file line number Diff line number Diff line change
Expand Up @@ -959,9 +959,18 @@ public function has_combined_unit_field(): bool {

// Furthermore, there must be either a {_0}{_u} without whitespace in the part's text
// (meaning the user explicitly wants a combined unit field) or no answer box placeholders
// at all, neither for the answer nor for the unit.
$combinedrequested = strpos($this->subqtext, '{_0}{_u}') !== false;
$noplaceholders = strpos($this->subqtext, '{_0}') === false && strpos($this->subqtext, '{_u}') === false;
// at all, neither for the answer nor for the unit. As the placeholders may contain formatting
// options, it makes sense to first simplify the part's question text by removing those. Note
// that the regex is different from e. g. the one in scan_for_answer_boxes(), because there
// MUST NOT be an :options-variable or a :MC/:MCE/:MCES/:MCS part.
$simplifiedtext = preg_replace(
'/\{(_u|_\d+)((\|[\w =#]*)*)\}/',
'{\1}',
$this->subqtext,
);

$combinedrequested = strpos($simplifiedtext, '{_0}{_u}') !== false;
$noplaceholders = strpos($simplifiedtext, '{_0}') === false && strpos($this->subqtext, '{_u}') === false;
return $combinedrequested || $noplaceholders;
}

Expand Down
10 changes: 8 additions & 2 deletions renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -666,10 +666,16 @@ public function get_part_formulation(question_attempt $qa, question_display_opti

// If part has combined unit answer input.
if ($part->has_combined_unit_field()) {
// For a combined unit field, we try to merge the formatting options from the {_0} and the
// {_u} placeholder, giving precedence to the latter.
$mergedformat = $boxes['_u']['format'] + $boxes['_0']['format'];
$combinedfieldhtml = $this->create_input_box(
$part, self::COMBINED_FIELD, $qa, $options, $boxes[$placeholder]['format'], $sub->feedbackclass
$part, self::COMBINED_FIELD, $qa, $options, $mergedformat, $sub->feedbackclass
);
return str_replace('{_0}{_u}', $combinedfieldhtml, $subqreplaced);
// The combined field must be placed where the user has the {_0}{_u} placeholders, possibly with
// their formatting options.
$boxplaceholders = $boxes['_0']['placeholder'] . $boxes['_u']['placeholder'];
return str_replace($boxplaceholders, $combinedfieldhtml, $subqreplaced);
}

// Iterate over all boxes again, this time creating the appropriate input control and insert it
Expand Down
79 changes: 79 additions & 0 deletions tests/renderer_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,85 @@ public function test_render_formatted_input_box($styles, $placeholder): void {
$this->check_current_output(...$expectations);
}

/**
* Data provider.
*
* @return array
*/
public static function provide_combined_box_formatting(): array {
return [
[[], '{_0}{_u}'],
[['width: 100px'], '{_0|w=100px}{_u}'],
[['width: 100px'], '{_0}{_u|w=100px}'],
[['width: 80px', 'background-color: blue'], '{_0|w=100px|bgcol=red}{_u|w=80px|bgcol=blue}'],
[['width: 100px', 'background-color: red'], '{_0|w=100px|bgcol=red}{_u}'],
[['width: 100px', 'background-color: red'], '{_0}{_u|w=100px|bgcol=red}'],
[['width: 80px', 'background-color: blue'], '{_0|w=100px|bgcol=red}{_u|w=80px|bgcol=blue}'],
[['width: 80px', 'background-color: blue', 'text-align: right'], '{_0|w=100px|align=right}{_u|w=80px|bgcol=blue}'],
];
}

/**
* Test formatting of combined unit field works as expected.
*
* @param array $styles (combined) style settings to be checked for
* @param string $placeholder placeholder definition with formatting
* @return void
*
* @dataProvider provide_combined_box_formatting
*/
public function test_formatting_of_combined_unit_box($styles, $placeholder): void {
$q = $this->get_test_formulas_question('testsinglenumunit');
$q->parts[0]->subqtext = $placeholder;
$this->start_attempt_at_question($q, 'immediatefeedback', 1);

// Check that there is a combined unit field and no other fields or stray placeholders.
$this->render();
$this->check_output_contains_text_input('0_');
$this->check_output_does_not_contain_text_input_with_class('0_0');
$this->check_output_does_not_contain_text_input_with_class('0_1');
$this->check_output_does_not_contain_stray_placeholders();

// Check the formatting.
$expectations = [];
foreach ($styles as $style) {
$expectations[] = $this->get_contains_input_with_css_expectation($style);
}
$this->check_current_output(...$expectations);
}

/**
* Test formatting of separate unit field works as expected.
*
* @param array $styles style settings to be checked for
* @param string $placeholder placeholder definition with formatting
* @return void
*
* @dataProvider provide_styles
*/
public function test_formatting_of_separate_unit_box($styles, $placeholder): void {
// We take the formatting intended for the number box and use it for the unit box. Also,
// we add a placeholder for an unformatted number box in front of it.
$placeholder = str_replace('{_0', '{_0} {_u', $placeholder);
$q = $this->get_test_formulas_question('testsinglenumunit');
$q->parts[0]->subqtext = $placeholder;
$this->start_attempt_at_question($q, 'immediatefeedback', 1);

// There must be a number box and a unit box, no combined field and no stray placeholders.
$this->render();
$this->check_output_contains_text_input('0_0');
$this->check_output_contains_text_input('0_1');
$this->check_output_does_not_contain_text_input_with_class('0_');
$this->check_output_does_not_contain_stray_placeholders();

// Check the formatting.
$expectations = [];
foreach ($styles as $style) {
$expectations[] = $this->get_contains_input_with_css_expectation($style);
}
$this->check_current_output(...$expectations);
}

/**
* Data provider.
*
Expand Down
Loading