Skip to content

Commit

Permalink
feat: style question inputs like Moodle
Browse files Browse the repository at this point in the history
Adds bootstrap classes to question inputs to roughly emulate Moodle's look-and-feel.
  • Loading branch information
MHajoha committed Sep 21, 2023
1 parent 124f225 commit c351754
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 6 deletions.
49 changes: 49 additions & 0 deletions classes/question_ui_renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ private function render_part(DOMNode $part, question_attempt $qa, ?question_disp
$this->hide_unwanted_feedback($xpath, $options);
$this->set_input_values_and_readonly($xpath, $qa, $options);
$this->shuffle_contents($xpath);
$this->add_styles($xpath);
$this->mangle_ids_and_names($xpath, $qa);
$this->clean_up($xpath);
$this->resolve_placeholders($xpath);
Expand Down Expand Up @@ -449,4 +450,52 @@ private function resolve_placeholders(DOMXPath $xpath): void {
}
}
}

/**
* Adds CSS classes to various elements to style them similarly to Moodle's own question types.
*
* @param DOMXPath $xpath
* @return void
*/
private function add_styles(DOMXPath $xpath): void {
/** @var DOMElement $element */
foreach ($xpath->query("
//xhtml:input[@type != 'checkbox' and @type != 'radio' and
@type != 'button' and @type != 'submit' and @type != 'reset']
| //xhtml:select | //xhtml:textarea
") as $element) {
$this->add_class_names($element, "form-control", "qpy-input");
}

foreach ($xpath->query("//xhtml:input[@type = 'button' or @type = 'submit' or @type = 'reset']
| //xhtml:button") as $element) {
$this->add_class_names($element, "btn", "btn-primary", "qpy-input");
}

foreach ($xpath->query("//xhtml:input[@type = 'checkbox' or @type = 'radio']") as $element) {
$this->add_class_names($element, "qpy-input");
}
}

/**
* Adds the given class names to the elements `class` attribute if not already present.
*
* @param DOMElement $element
* @param string ...$newclasses
* @return void
*/
private function add_class_names(DOMElement $element, string ...$newclasses): void {
$classarray = [];
for ($class = strtok($element->getAttribute("class"), " \t\n"); $class; $class = strtok(" \t\n")) {
$classarray[] = $class;
}

foreach ($newclasses as $newclass) {
if (!in_array($newclass, $classarray)) {
$classarray[] = $newclass;
}
}

$element->setAttribute("class", implode(" ", $classarray));
}
}
7 changes: 7 additions & 0 deletions styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,10 @@
.qpy-repetition-remove {
margin: .5em;
}

.form-control.qpy-input {
/* Matches the styling used by most bundled question types. */
display: inline;
width: auto;
vertical-align: baseline;
}
12 changes: 6 additions & 6 deletions tests/question_ui_renderer_test.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,15 +224,15 @@ public function test_should_mangle_names() {

$this->assertXmlStringEqualsXmlString(<<<EXPECTED
<div xmlns="http://www.w3.org/1999/xhtml">
<input name="mangled:my_number" type="number"/>
<select name="mangled:my_select">
<input class="form-control qpy-input" name="mangled:my_number" type="number"/>
<select class="form-control qpy-input" name="mangled:my_select">
<option value="1">One</option>
<option value="2">Two</option>
</select>
<input type="radio" name="mangled:my_radio" value="1">One</input>
<input type="radio" name="mangled:my_radio" value="2">Two</input>
<textarea name="mangled:my_text"/>
<button name="mangled:my_button">Click me!</button>
<input class="qpy-input" type="radio" name="mangled:my_radio" value="1">One</input>
<input class="qpy-input" type="radio" name="mangled:my_radio" value="2">Two</input>
<textarea class="form-control qpy-input" name="mangled:my_text"/>
<button class="btn btn-primary qpy-input" name="mangled:my_button">Click me!</button>
</div>
EXPECTED, $result);
}
Expand Down

0 comments on commit c351754

Please sign in to comment.