Skip to content
Snippets Groups Projects
Commit 339493db authored by Elmar Ludwig's avatar Elmar Ludwig
Browse files

add Vips as CorePlugin, re #4258

Merge request studip/studip!3432
parent 10636268
No related branches found
No related tags found
No related merge requests found
Showing
with 6782 additions and 0 deletions
<?php
/**
* vips/admin.php - course administration controller
*
* This program 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 2 of
* the License, or (at your option) any later version.
*
* @author Elmar Ludwig
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
*/
class Vips_AdminController extends AuthenticatedController
{
/**
* Edit or create a block in the course.
*/
public function edit_block_action()
{
Navigation::activateItem('/course/vips/sheets');
PageLayout::setHelpKeyword('Basis.Vips');
$block_id = Request::int('block_id');
if ($block_id) {
$block = VipsBlock::find($block_id);
} else {
$block = new VipsBlock();
$block->range_id = Context::getId();
}
VipsModule::requireStatus('tutor', $block->range_id);
$this->block = $block;
$this->groups = Statusgruppen::findBySeminar_id($block->range_id);
}
/**
* Store changes to a block.
*/
public function store_block_action()
{
CSRFProtection::verifyUnsafeRequest();
$block_id = Request::int('block_id');
$group_id = Request::option('group_id');
if ($block_id) {
$block = VipsBlock::find($block_id);
} else {
$block = new VipsBlock();
$block->range_id = Context::getId();
}
VipsModule::requireStatus('tutor', $block->range_id);
$block->name = Request::get('block_name');
$block->group_id = $group_id ?: null;
$block->visible = $group_id !== '';
if (!Request::int('block_grouped')) {
$block->weight = null;
} else if ($block->weight === null) {
$block->weight = 0;
if ($block_id) {
// sum up individual assignment weights for total block weight
foreach (VipsAssignment::findByBlock_id($block_id) as $assignment) {
$block->weight += $assignment->weight;
}
}
}
$block->store();
PageLayout::postSuccess(sprintf(_('Der Block „%s“ wurde gespeichert.'), htmlReady($block->name)));
$this->redirect($this->url_for('vips/sheets', ['group' => 1]));
}
/**
* Delete a block from the course.
*/
public function delete_block_action()
{
CSRFProtection::verifyUnsafeRequest();
$block_id = Request::int('block_id');
$block = VipsBlock::find($block_id);
$block_name = $block->name;
VipsModule::requireStatus('tutor', $block->range_id);
if ($block->delete()) {
PageLayout::postSuccess(sprintf(_('Der Block „%s“ wurde gelöscht.'), htmlReady($block_name)));
}
$this->redirect('vips/sheets');
}
/**
* Stores the weights of blocks, sheets and exams
*/
public function store_weight_action()
{
CSRFProtection::verifyUnsafeRequest();
$assignment_weight = Request::floatArray('assignment_weight');
$block_weight = Request::floatArray('block_weight');
foreach ($assignment_weight as $assignment_id => $weight) {
$assignment = VipsAssignment::find($assignment_id);
VipsModule::requireEditPermission($assignment);
$assignment->weight = $weight;
$assignment->store();
}
foreach ($block_weight as $block_id => $weight) {
$block = VipsBlock::find($block_id);
VipsModule::requireStatus('tutor', $block->range_id);
$block->weight = $weight;
$block->store();
}
$this->redirect('vips/solutions');
}
/**
* Edit the grade distribution settings.
*/
public function edit_grades_action()
{
Navigation::activateItem('/course/vips/solutions');
PageLayout::setHelpKeyword('Basis.VipsErgebnisse');
$course_id = Context::getId();
VipsModule::requireStatus('tutor', $course_id);
$grades = ['1,0', '1,3', '1,7', '2,0', '2,3', '2,7', '3,0', '3,3', '3,7', '4,0'];
$percentages = array_fill(0, count($grades), '');
$comments = array_fill(0, count($grades), '');
$settings = CourseConfig::get($course_id);
foreach ($settings->VIPS_COURSE_GRADES as $value) {
$index = array_search($value['grade'], $grades);
if ($index !== false) {
$percentages[$index] = $value['percent'];
$comments[$index] = $value['comment'];
}
}
$this->grades = $grades;
$this->grade_settings = $settings->VIPS_COURSE_GRADES;
$this->percentages = $percentages;
$this->comments = $comments;
}
/**
* Stores the distribution of grades
*/
public function store_grades_action()
{
CSRFProtection::verifyUnsafeRequest();
$course_id = Context::getId();
VipsModule::requireStatus('tutor', $course_id);
$grades = ['1,0', '1,3', '1,7', '2,0', '2,3', '2,7', '3,0', '3,3', '3,7', '4,0'];
$percentages = Request::floatArray('percentage');
$comments = Request::getArray('comment');
$grade_settings = [];
$percent_last = 101;
$error = false;
foreach ($percentages as $i => $percent) {
if ($percent) {
$grade_settings[] = [
'grade' => $grades[$i],
'percent' => $percent,
'comment' => trim($comments[$i])
];
if ($percent < 0 || $percent > 100) {
PageLayout::postError(_('Die Notenwerte müssen zwischen 0 und 100 liegen!'));
$error = true;
} else if ($percent_last <= $percent) {
PageLayout::postError(sprintf(_('Die Notenwerte müssen monoton absteigen (%s > %s)!'), $percent_last, $percent));
$error = true;
}
$percent_last = $percent;
}
}
if (!$error) {
$settings = CourseConfig::get($course_id);
$settings->store('VIPS_COURSE_GRADES', $grade_settings);
PageLayout::postSuccess(_('Die Notenwerte wurden eingetragen.'));
}
$this->redirect('vips/solutions');
}
}
<?php
/**
* vips/api.php - API controller for Vips
*
* This program 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 2 of
* the License, or (at your option) any later version.
*
* @author Elmar Ludwig
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
*/
class Vips_ApiController extends AuthenticatedController
{
public function assignments_action($range_id)
{
if ($range_id !== $GLOBALS['user']->id) {
VipsModule::requireStatus('tutor', $range_id);
}
$assignments = VipsAssignment::findByRangeId($range_id);
$data = [];
foreach ($assignments as $assignment) {
if ($assignment->type !== 'exam') {
$data[] = [
'id' => (string) $assignment->id,
'title' => $assignment->test->title,
'type' => $assignment->type,
'icon' => $assignment->getTypeIcon()->getShape(),
'start' => date('d.m.Y, H:i', $assignment->start),
'end' => date('d.m.Y, H:i', $assignment->end),
'active' => $assignment->active,
'block' => $assignment->block_id ? $assignment->block->name : null
];
}
}
$this->render_json($data);
}
public function assignment_action($assignment_id)
{
$assignment = VipsAssignment::find($assignment_id);
$user_id = $GLOBALS['user']->id;
VipsModule::requireViewPermission($assignment);
$released = $assignment->releaseStatus($user_id);
if ($assignment->type === 'exam') {
throw new AccessDeniedException(_('Sie haben keinen Zugriff auf dieses Aufgabenblatt!'));
}
if (
!$assignment->checkAccess($user_id)
&& $released < VipsAssignment::RELEASE_STATUS_CORRECTIONS
) {
throw new AccessDeniedException(_('Das Aufgabenblatt kann zur Zeit nicht bearbeitet werden.'));
}
// enter user start time the moment he/she first clicks on any exercise
if (!$assignment->checkEditPermission()) {
$assignment->recordAssignmentAttempt($user_id);
}
$data = [
'id' => (string) $assignment->id,
'title' => $assignment->test->title,
'type' => $assignment->type,
'icon' => $assignment->getTypeIcon()->getShape(),
'start' => date('d.m.Y, H:i', $assignment->start),
'end' => date('d.m.Y, H:i', $assignment->end),
'active' => $assignment->active,
'block' => $assignment->block_id ? $assignment->block->name : null,
'reset_allowed' => $assignment->isRunning($user_id) && $assignment->isResetAllowed(),
'points' => $assignment->test->getTotalPoints(),
'release_status' => $released,
'exercises' => []
];
foreach ($assignment->getExerciseRefs($user_id) as $exercise_ref) {
$template = $this->courseware_template($assignment, $exercise_ref, $released);
$exercise = $exercise_ref->exercise;
$data['exercises'][] = [
'id' => $exercise->id,
'type' => $exercise->type,
'title' => $exercise->title,
'template' => $template->render(),
'item_count' => $exercise->itemCount(),
'show_solution' => $template->show_solution
];
}
$this->render_json($data);
}
public function exercise_action($assignment_id, $exercise_id)
{
$assignment = VipsAssignment::find($assignment_id);
$user_id = $GLOBALS['user']->id;
VipsModule::requireViewPermission($assignment, $exercise_id);
$released = $assignment->releaseStatus($user_id);
if ($assignment->type === 'exam') {
throw new AccessDeniedException(_('Sie haben keinen Zugriff auf dieses Aufgabenblatt!'));
}
if (
!$assignment->checkAccess($user_id)
&& $released < VipsAssignment::RELEASE_STATUS_CORRECTIONS
) {
throw new AccessDeniedException(_('Das Aufgabenblatt kann zur Zeit nicht bearbeitet werden.'));
}
// enter user start time the moment he/she first clicks on any exercise
if (!$assignment->checkEditPermission()) {
$assignment->recordAssignmentAttempt($user_id);
}
$exercise_ref = VipsExerciseRef::find([$assignment->test_id, $exercise_id]);
$template = $this->courseware_template($assignment, $exercise_ref, $released);
$exercise = $exercise_ref->exercise;
$data = [
'id' => $exercise->id,
'type' => $exercise->type,
'title' => $exercise->title,
'template' => $template->render(),
'item_count' => $exercise->itemCount(),
'show_solution' => $template->show_solution
];
$this->render_json($data);
}
private function courseware_template($assignment, $exercise_ref, $released)
{
$user_id = $GLOBALS['user']->id;
$exercise = $exercise_ref->exercise;
$solution = $assignment->getSolution($user_id, $exercise->id);
$max_tries = $assignment->getMaxTries();
$max_points = $exercise_ref->points;
$sample_solution = false;
$show_solution = false;
$tries_left = null;
if ($assignment->isRunning($user_id)) {
// if a solution has been submitted during a selftest
if ($max_tries && $solution) {
$tries_left = $max_tries - $solution->countTries();
if (
$solution->points == $max_points
|| !$solution->state
|| $solution->grader_id
|| $tries_left <= 0
) {
$show_solution = true;
$sample_solution = true;
}
}
} else {
$show_solution = true;
$sample_solution = $released == VipsAssignment::RELEASE_STATUS_SAMPLE_SOLUTIONS;
if (!$solution) {
$solution = new VipsSolution();
$solution->assignment = $assignment;
}
}
$template = $this->get_template_factory()->open('vips/exercises/courseware_block');
$template->user_id = $user_id;
$template->assignment = $assignment;
$template->exercise = $exercise;
$template->tries_left = $tries_left;
$template->solution = $solution;
$template->max_points = $max_points;
$template->sample_solution = $sample_solution;
$template->show_solution = $show_solution;
return $template;
}
public function solution_action($assignment_id, $exercise_id)
{
CSRFProtection::verifyUnsafeRequest();
$assignment = VipsAssignment::find($assignment_id);
$block_id = Request::int('block_id');
$user_id = $GLOBALS['user']->id;
VipsModule::requireViewPermission($assignment, $exercise_id);
// check access to courseware block
if ($block_id) {
$block = Courseware\Block::find($block_id);
$payload = $block->type->getPayload();
if ($payload['assignment'] != $assignment_id) {
throw new AccessDeniedException(_('Sie haben keinen Zugriff auf diesen Block!'));
}
}
if ($assignment->type === 'exam') {
throw new AccessDeniedException(_('Sie haben keinen Zugriff auf dieses Aufgabenblatt!'));
}
if (!$assignment->checkAccess($user_id)) {
throw new AccessDeniedException(_('Das Aufgabenblatt kann zur Zeit nicht bearbeitet werden.'));
}
// enter user start time the moment he/she first clicks on any exercise
if (!$assignment->checkEditPermission()) {
$assignment->recordAssignmentAttempt($user_id);
}
if (Request::isPost()) {
$request = Request::getInstance();
$exercise = Exercise::find($exercise_id);
$solution = $exercise->getSolutionFromRequest($request, $_FILES);
$solution->user_id = $user_id;
if ($solution->isEmpty()) {
$this->set_status(422);
} else {
$assignment->storeSolution($solution);
$this->set_status(201);
}
}
if (Request::isDelete()) {
if ($assignment->isResetAllowed()) {
$assignment->deleteSolution($user_id, $exercise_id);
$this->set_status(204);
} else {
$this->set_status(403);
}
}
// update user progress in Courseware
if ($block_id) {
$progress = new Courseware\UserProgress([$user_id, $block_id]);
$progress->grade = $assignment->getUserProgress($user_id);
$progress->store();
}
$this->render_nothing();
}
}
<?php
/**
* vips/config.php - global configuration controller
*
* This program 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 2 of
* the License, or (at your option) any later version.
*
* @author Elmar Ludwig
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
*/
class Vips_ConfigController extends AuthenticatedController
{
/**
* Callback function being called before an action is executed. If this
* function does not return FALSE, the action will be called, otherwise
* an error will be generated and processing will be aborted. If this function
* already #rendered or #redirected, further processing of the action is
* withheld.
*
* @param string Name of the action to perform.
* @param array An array of arguments to the action.
*
* @return bool|void
*/
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
$GLOBALS['perm']->check('root');
Navigation::activateItem('/admin/config/vips');
PageLayout::setHelpKeyword('Basis.VipsEinstellungen');
PageLayout::setTitle(_('Einstellungen für Aufgaben'));
}
public function index_action()
{
$this->fields = DataField::getDataFields('user');
$this->config = Config::get();
$widget = new ActionsWidget();
$widget->addLink(
_('Anstehende Klausuren anzeigen'),
$this->pending_assignmentsURL(),
Icon::create('doctoral_cap')
)->asDialog('size=big');
Sidebar::get()->addWidget($widget);
}
public function save_action()
{
CSRFProtection::verifyUnsafeRequest();
$exam_mode = Request::int('exam_mode', 0);
$exam_terms = trim(Request::get('exam_terms'));
$exam_terms = Studip\Markup::purifyHtml($exam_terms);
$config = Config::get();
$config->store('VIPS_EXAM_RESTRICTIONS', $exam_mode);
$config->store('VIPS_EXAM_TERMS', $exam_terms);
$room = Request::getArray('room');
$ip_range = Request::getArray('ip_range');
$ip_ranges = [];
foreach ($room as $i => $name) {
$name = preg_replace('/[ ,]+/', '_', trim($name));
if ($name !== '') {
$ip_ranges[$name] = trim($ip_range[$i]);
}
}
if ($ip_ranges) {
ksort($ip_ranges);
$config->store('VIPS_EXAM_ROOMS', $ip_ranges);
}
PageLayout::postSuccess(_('Die Einstellungen wurden gespeichert.'));
$this->redirect('vips/config');
}
public function pending_assignments_action()
{
$this->assignments = VipsAssignment::findBySQL(
"range_type = 'course' AND type = 'exam' AND
start BETWEEN UNIX_TIMESTAMP(NOW() - INTERVAL 1 DAY) AND UNIX_TIMESTAMP(NOW() + INTERVAL 14 DAY) AND end > UNIX_TIMESTAMP()
ORDER BY start"
);
}
}
<?php
/**
* vips/exam_mode.php - restricted exam mode controller
*
* This program 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 2 of
* the License, or (at your option) any later version.
*
* @author Elmar Ludwig
* @license http://www.gnu.org/licenses/gpl-2.0.html GPL version 2
*/
class Vips_ExamModeController extends AuthenticatedController
{
/**
* Display a list of courses with currently active tests of type 'exam'.
* Only used when there are multiple courses with running exams.
*/
public function index_action()
{
PageLayout::setTitle(_('Klausurübersicht'));
Helpbar::get()->addPlainText('',
_('Der normale Betrieb von Stud.IP ist für Sie zur Zeit gesperrt, da Klausuren geschrieben werden.'));
$this->courses = VipsModule::getCoursesWithRunningExams($GLOBALS['user']->id);
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
/**
* @var Vips_AdminController $controller
* @var VipsBlock $block
* @var VipsGroup[] $groups
*/
?>
<form class="default" action="<?= $controller->link_for('vips/admin/store_block') ?>" data-secure method="POST">
<?= CSRFProtection::tokenTag() ?>
<? if ($block->id): ?>
<input type="hidden" name="block_id" value="<?= $block->id ?>">
<? endif ?>
<label>
<span class="required"><?= _('Blockname') ?></span>
<input type="text" name="block_name" required value="<?= htmlReady($block->name) ?>">
</label>
<label>
<?= _('Sichtbarkeit') ?>
<?= tooltipIcon(_('Blöcke und zugeordnete Aufgabenblätter können nur für bestimmte Gruppen sichtbar oder auch komplett unsichtbar gemacht werden.')) ?>
<select name="group_id">
<option value="0">
<?= _('Alle Teilnehmenden (keine Beschränkung)') ?>
</option>
<option value="" <?= !$block->visible ? 'selected' : '' ?>>
<?= _('Für Teilnehmende unsichtbar') ?>
</option>
<? foreach ($groups as $group): ?>
<option value="<?= $group->id ?>" <?= $block->group_id === $group->id ? 'selected' : '' ?>>
<?= sprintf(_('Gruppe „%s“'), htmlReady($group->name)) ?>
</option>
<? endforeach ?>
</select>
</label>
<label>
<input type="checkbox" name="block_grouped" value="1" <?= $block->weight !== null ? 'checked' : '' ?>>
<?= _('Aufgabenblätter in der Bewertung gruppieren') ?>
<?= tooltipIcon(_('In der Ergebnisübersicht wird nur der Block anstelle der enthaltenen Aufgabenblätter aufgeführt.')) ?>
</label>
<footer data-dialog-button>
<?= Studip\Button::createAccept(_('Speichern'), 'store_block') ?>
</footer>
</form>
<?php
/**
* @var Vips_AdminController $controller
* @var array $grades
* @var bool $grade_settings
* @var array $percentages
* @var string[] $comments
*/
?>
<? setlocale(LC_NUMERIC, $_SESSION['_language'] . '.UTF-8') ?>
<form class="default" action="<?= $controller->link_for('vips/admin/store_grades') ?>" data-secure method="post">
<?= CSRFProtection::tokenTag() ?>
<table class="default">
<caption>
<?= _('Notenverteilung') ?>
</caption>
<thead>
<tr>
<th><?= _('Note') ?></th>
<th><?= _('Schwellwert') ?></th>
<th><?= _('Kommentar') ?></th>
</tr>
</thead>
<tbody>
<? for ($i = 0; $i < count($grades); ++$i): ?>
<? $class = $grade_settings && !$percentages[$i] ? 'quiet' : '' ?>
<tr class="<?= $class ?>">
<td><?= htmlReady($grades[$i]) ?></td>
<td>
<input type="text" class="percent_input" name="percentage[<?= $i ?>]" value="<?= sprintf('%g', $percentages[$i]) ?>"> %
</td>
<td>
<input type="text" name="comment[<?= $i ?>]" value="<?= htmlReady($comments[$i]) ?>" <?= $class ? 'disabled' : '' ?>>
</td>
</tr>
<? endfor ?>
</tbody>
<tfoot>
<tr>
<td class="smaller" colspan="3">
<?= _('Wenn Sie eine bestimmte Notenstufe nicht verwenden wollen, lassen Sie das Feld für den Schwellwert leer.') ?>
</td>
</tr>
</tfoot>
</table>
<footer data-dialog-button>
<?= Studip\Button::createAccept(_('Speichern'), 'save') ?>
</footer>
</form>
<? setlocale(LC_NUMERIC, 'C') ?>
<?php
/**
* @var Vips_ConfigController $controller
* @var Config $config
*/
?>
<form class="default width-1200" action="<?= $controller->link_for('vips/config/save') ?>" data-secure method="post">
<?= CSRFProtection::tokenTag() ?>
<button hidden name="save"></button>
<fieldset>
<legend>
<?= _('Einstellungen für Klausuren') ?>
</legend>
<div class="label-text">
<?= _('Klausurmodus aktivieren') ?>
</div>
<label class="undecorated">
<input type="checkbox" name="exam_mode" value="1" <?= $config->VIPS_EXAM_RESTRICTIONS ? 'checked' : '' ?>>
<?= _('Während einer Klausur den Zugriff auf andere Bereiche von Stud.IP sperren') ?>
<?= tooltipIcon(_('Gilt nur für Klausuren mit beschränktem IP-Zugriffsbereich.')) ?>
</label>
<div class="label-text">
<?= _('Vordefinierte IP-Bereiche für PC-Räume') ?>
</div>
<table class="default">
<thead>
<tr>
<th style="width: 20%;">
<?= _('Raum') ?>
</th>
<th style="width: 75%;">
<?= _('IP-Bereiche') ?>
<?= tooltipIcon($this->render_partial('vips/sheets/ip_range_tooltip'), false, true) ?>
</th>
<th class="actions">
<?= _('Löschen') ?>
</th>
</tr>
</thead>
<tbody class="dynamic_list">
<? foreach ($config->VIPS_EXAM_ROOMS ?: [] as $room => $ip_range): ?>
<tr class="dynamic_row">
<td>
<input type="text" name="room[]" value="<?= htmlReady($room) ?>">
</td>
<td>
<input type="text" class="size-l validate_ip_range" name="ip_range[]" value="<?= htmlReady($ip_range) ?>">
</td>
<td class="actions">
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Eintrag löschen')]) ?>
</td>
</tr>
<? endforeach ?>
<tr class="dynamic_row template">
<td>
<input type="text" name="room[]">
</td>
<td>
<input type="text" class="size-l validate_ip_range" name="ip_range[]">
</td>
<td class="actions">
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Eintrag löschen')]) ?>
</td>
</tr>
<tr>
<th colspan="3">
<?= Studip\Button::create(_('Eintrag hinzufügen'), 'add_room', ['class' => 'add_dynamic_row']) ?>
</th>
</tr>
</tbody>
</table>
<label>
<?= _('Teilnahmebedingungen vor Beginn einer Klausur') ?>
<textarea name="exam_terms" class="size-l wysiwyg"><?= wysiwygReady($config->VIPS_EXAM_TERMS) ?></textarea>
</label>
</fieldset>
<footer>
<?= Studip\Button::createAccept(_('Speichern'), 'save') ?>
</footer>
</form>
<?php
/**
* @var Vips_ConfigController $controller
* @var VipsAssignment[] $assignments
*/
?>
<? if (count($assignments) === 0): ?>
<?= MessageBox::info(_('Es gibt zur Zeit keine anstehenden Klausuren.')) ?>
<? else: ?>
<table class="default sortable-table" data-sortlist="[[1,0]]">
<caption>
<?= _('Klausuren') ?>
<div class="actions">
<?= sprintf(ngettext('%d Klausur', '%d Klausuren', count($assignments)), count($assignments)) ?>
</div>
</caption>
<thead>
<tr class="sortable">
<th data-sort="text" style="width: 35%;">
<?= _('Titel') ?>
</th>
<th data-sort="text" style="width: 10%;">
<?= _('Start') ?>
</th>
<th data-sort="text" style="width: 10%;">
<?= _('Ende') ?>
</th>
<th data-sort="text" style="width: 15%;">
<?= _('Autor/-in') ?>
</th>
<th data-sort="text" style="width: 30%;">
<?= _('Veranstaltung') ?>
</th>
</tr>
</thead>
<tbody>
<? foreach ($assignments as $assignment): ?>
<tr>
<td>
<a href="<?= $controller->link_for('vips/sheets/edit_assignment', ['cid' => $assignment->range_id, 'assignment_id' => $assignment->id]) ?>">
<?= $assignment->getTypeIcon() ?>
<?= htmlReady($assignment->test->title) ?>
</a>
<? if ($assignment->isRunning() && !$assignment->active): ?>
(<?= _('unterbrochen') ?>)
<? endif ?>
</td>
<td data-text="<?= htmlReady($assignment->start) ?>">
<?= date('d.m.Y, H:i', $assignment->start) ?>
</td>
<td data-text="<?= htmlReady($assignment->end) ?>">
<?= date('d.m.Y, H:i', $assignment->end) ?>
</td>
<td>
<?= htmlReady($assignment->test->user->getFullName('no_title_rev')) ?>
</td>
<td>
<a href="<?= URLHelper::getLink('seminar_main.php', ['cid' => $assignment->range_id]) ?>">
<?= htmlReady($assignment->course->name) ?>
</a>
</td>
</tr>
<? endforeach ?>
</tbody>
</table>
<? endif ?>
<?php
/**
* @var array $courses
*/
?>
<? if (count($courses)) : ?>
<table class="default width-1200">
<caption>
<?= _('Bitte wählen Sie den Kurs, in dem Sie die Klausur schreiben möchten:') ?>
</caption>
<thead>
<tr>
<th style="width: 5%;"></th>
<th style="width: 65%;"><?= _('Name') ?></th>
<th style="width: 30%;"><?= _('Inhalt') ?></th>
</tr>
</thead>
<tbody>
<? foreach ($courses as $course_id => $course_name) : ?>
<? $nav = VipsModule::$instance->getIconNavigation($course_id, null, null) ?>
<? if ($nav): ?>
<tr>
<td>
<?= CourseAvatar::getAvatar($course_id)->getImageTag(Avatar::SMALL) ?>
</td>
<td>
<a href="<?= URLHelper::getLink($nav->getURL(), ['cid' => $course_id]) ?>">
<?= htmlReady($course_name) ?>
</a>
</td>
<td>
<a href="<?= URLHelper::getLink($nav->getURL(), ['cid' => $course_id]) ?>">
<?= $nav->getImage()->asImg($nav->getLinkAttributes()) ?>
</a>
</td>
</tr>
<? endif ?>
<? endforeach ?>
</tbody>
</table>
<? else : ?>
<? /* this should never be shown, but can be reached directly by URL */ ?>
<?= MessageBox::info(_('Zur Zeit laufen keine Klausuren.')) ?>
<? endif ?>
<?php
/**
* @var Exercise $exercise
* @var VipsSolution $solution
* @var array $results
* @var array $response
* @var bool $show_solution
*/
?>
<div class="description">
<!--
<? foreach (explode('[[]]', formatReady($exercise->task['text'])) as $blank => $text) : ?>
--><?= $text ?><!--
<? if (isset($exercise->task['answers'][$blank])) : ?>
<? if ($solution->id): ?>
<? if ($results[$blank]['points'] == 1): ?>
--><span class="correct_item math-tex"><?= htmlReady($response[$blank]) ?><!--
--><?= Icon::create('accept', Icon::ROLE_STATUS_GREEN)->asImg(['class' => 'correction_inline', 'title' => _('richtig')]) ?><!--
--></span><!--
<? elseif ($results[$blank]['points'] == 0.5): ?>
--><span class="fuzzy_item math-tex"><?= htmlReady($response[$blank]) ?><!--
--><?= Icon::create('decline', Icon::ROLE_STATUS_YELLOW)->asImg(['class' => 'correction_inline', 'title' => _('fast richtig')]) ?><!--
--></span><!--
<? elseif (empty($edit_solution) || $results[$blank]['safe']): ?>
--><span class="wrong_item math-tex"><?= htmlReady($response[$blank]) ?><!--
--><?= Icon::create('decline', Icon::ROLE_STATUS_RED)->asImg(['class' => 'correction_inline', 'title' => _('falsch')]) ?><!--
--></span><!--
<? else: ?>
--><span class="wrong_item math-tex"><?= htmlReady($response[$blank]) ?><!--
--><?= Icon::create('question', Icon::ROLE_STATUS_RED)->asImg(['class' => 'correction_inline', 'title' => _('unbekannte Antwort')]) ?><!--
--></span><!--
<? endif ?>
<? endif ?>
<? if ($show_solution && (empty($results) || $results[$blank]['points'] < 1) && $exercise->correctAnswers($blank)): ?>
--><span class="correct_item math-tex"><?= htmlReady(implode(' | ', $exercise->correctAnswers($blank))) ?></span><!--
<? endif ?>
<? endif ?>
<? endforeach ?>
-->
</div>
<?= $this->render_partial('exercises/evaluation_mode_info', ['evaluation_mode' => false]) ?>
<?php
/**
* @var ClozeTask $exercise
*/
?>
<? $tooltip = sprintf('<p>%s:<br>[[ ... ]]</p><p>%s:<br>[[ ... | ... | ... ]]</p><p>%s:<br>[[ ... | ... | *... ]]</p><p>%s:<br>[[: ... | ... | *... ]]</p>',
_('Lücke hinzufügen'), _('Mehrere Lösungen mit | trennen'), _('Falsche Antworten mit * markieren'), _('Auswahl aus Liste statt Eingabe')) ?>
<label>
<?= _('Lückentext') ?> <?= tooltipIcon($tooltip, false, true) ?>
<? $cloze_text = $exercise->getClozeText() ?>
<textarea name="cloze_text" class="character_input size-l wysiwyg" rows="<?= $exercise->textareaSize($cloze_text) ?>"><?= wysiwygReady($cloze_text) ?></textarea>
</label>
<label>
<?= _('Antwortmodus') ?>
<select name="layout" onchange="$(this).parent().next().toggle(this.value === '')">
<option value="">
<?= _('Texteingabe') ?>
</option>
<option value="select" <?= $exercise->interactionType() === 'select' ? 'selected' : '' ?>>
<?= _('Antwort aus Liste auswählen') ?>
</option>
<option value="drag" <?= $exercise->interactionType() === 'drag' ? 'selected' : '' ?>>
<?= _('Antwort in das Feld ziehen') ?>
</option>
</select>
</label>
<div style="<?= $exercise->interactionType() !== 'input' ? 'display: none;' : '' ?>">
<label>
<?= _('Art des Textvergleichs') ?>
<select name="compare" onchange="$(this).parent().next('label').toggle($(this).val() === 'numeric')">
<option value="">
<?= _('Groß-/Kleinschreibung unterscheiden') ?>
</option>
<option value="ignorecase" <?= isset($exercise->task['compare']) && $exercise->task['compare'] === 'ignorecase' ? 'selected' : '' ?>>
<?= _('Groß-/Kleinschreibung ignorieren') ?>
</option>
<option value="numeric" <?= isset($exercise->task['compare']) && $exercise->task['compare'] === 'numeric' ? 'selected' : '' ?>>
<?= _('Numerischer Wertevergleich (ggf. mit Einheit)') ?>
</option>
</select>
</label>
<label style="<?= isset($exercise->task['compare']) && $exercise->task['compare'] === 'numeric' ? '' : 'display: none;' ?>">
<?= _('Erlaubte relative Abweichung vom korrekten Wert') ?>
<br>
<input type="text" class="size-s" style="display: inline; text-align: right;"
name="epsilon" value="<?= isset($exercise->task['epsilon']) ? sprintf('%g', $exercise->task['epsilon'] * 100) : '0' ?>"> %
</label>
<label>
<input type="checkbox" <?= isset($exercise->task['input_width']) ? 'checked' : '' ?> onchange="$(this).next('select').attr('disabled', !this.checked)">
<?= _('Feste Breite der Eingabefelder:') ?>
<select name="input_width" style="display: inline; width: auto;" <?= isset($exercise->task['input_width']) ? '' : 'disabled' ?>>
<? foreach ([_('kurz'), _('mittel'), _('lang'), _('maximal')] as $key => $label): ?>
<option value="<?= $key ?>" <?= isset($exercise->task['input_width']) && $exercise->task['input_width'] == $key ? 'selected' : '' ?>>
<?= htmlReady($label) ?>
</option>
<? endforeach ?>
</select>
</label>
</div>
<?php
/**
* @var ClozeTask $exercise
* @var VipsSolution $solution
* @var array $response
* @var array $results
* @var bool $print_correction
* @var bool $show_solution
*/
?>
<div class="description">
<!--
<? foreach (explode('[[]]', formatReady($exercise->task['text'])) as $blank => $text): ?>
--><?= $text ?><!--
<? if (isset($exercise->task['answers'][$blank])) : ?>
<? if ($solution->id && $response[$blank] !== ''): ?>
--><span class="math-tex" style="text-decoration: underline;">&nbsp;&nbsp;<?= htmlReady($response[$blank]) ?>&nbsp;&nbsp;</span><!--
<? if ($print_correction): ?>
<? if ($results[$blank]['points'] == 1): ?>
--><?= Icon::create('accept', Icon::ROLE_STATUS_GREEN)->asImg(['title' => _('richtig')]) ?><!--
<? elseif ($results[$blank]['points'] == 0.5): ?>
--><?= Icon::create('decline', Icon::ROLE_STATUS_YELLOW)->asImg(['title' => _('fast richtig')]) ?><!--
<? else: ?>
--><?= Icon::create('decline', Icon::ROLE_STATUS_RED)->asImg(['title' => _('falsch')]) ?><!--
<? endif ?>
<? endif ?>
<? elseif ($exercise->isSelect($blank)): ?>
<? foreach ($exercise->task['answers'][$blank] as $index => $option) : ?>
--><?= $index ? ' | ' : '' ?><!--
--><?= Assets::img('choice_unchecked.svg', ['style' => 'vertical-align: text-bottom;']) ?> <!--
--><span class="math-tex" style="border-bottom: 1px dotted black;"><?= htmlReady($option['text']) ?></span><!--
<? endforeach ?>
<? else: ?>
--><?= str_repeat('_', $exercise->getInputWidth($blank)) ?><!--
<? endif ?>
<? if ($show_solution && (empty($results) || $results[$blank]['points'] < 1) && $exercise->correctAnswers($blank)): ?>
--><span class="correct_item math-tex"><?= htmlReady(implode(' | ', $exercise->correctAnswers($blank))) ?></span><!--
<? endif ?>
<? endif ?>
<? endforeach ?>
-->
</div>
<? if ($exercise->interactionType() === 'drag'): ?>
<div class="label-text">
<? if ($print_correction): ?>
<?= _('Nicht zugeordnete Antworten:') ?>
<? else: ?>
<?= _('Antwortmöglichkeiten:') ?>
<? endif ?>
</div>
<ol>
<? foreach ($exercise->availableAnswers($solution) as $item): ?>
<li>
<span class="math-tex"><?= htmlReady($item) ?></span>
</li>
<? endforeach ?>
</ol>
<? endif ?>
<?= $this->render_partial('exercises/evaluation_mode_info', ['evaluation_mode' => false]) ?>
<?php
/**
* @var ClozeTask $exercise
* @var VipsSolution $solution
* @var array $response
*/
?>
<div class="description">
<!--
<? foreach (explode('[[]]', formatReady($exercise->task['text'])) as $blank => $text): ?>
--><?= $text ?><!--
<? if (isset($exercise->task['answers'][$blank])) : ?>
<? if ($exercise->interactionType() === 'drag'): ?>
--><span class="cloze_drop math-tex" title="<?= _('Elemente hier ablegen') ?>">
<input type="hidden" name="answer[<?= $blank ?>]" value="<?= htmlReady($response[$blank] ?? '') ?>">
<? if (isset($response[$blank]) && $response[$blank] !== ''): ?>
<span class="cloze_item drag-handle" data-value="<?= htmlReady($response[$blank]) ?>"><?= htmlReady($response[$blank]) ?></span>
<? endif ?>
</span><!--
<? elseif ($exercise->isSelect($blank)): ?>
--><select class="cloze_select" name="answer[<?= $blank ?>]">
<? if ($exercise->task['answers'][$blank][0]['text'] !== ''): ?>
<option value="">&nbsp;</option>
<? endif ?>
<? foreach ($exercise->task['answers'][$blank] as $option): ?>
<option value="<?= htmlReady($option['text']) ?>" <?= trim($option['text']) === ($response[$blank] ?? '') ? ' selected' : '' ?>>
<?= htmlReady($option['text']) ?>
</option>
<? endforeach ?>
</select><!--
<? else: ?>
--><input type="text" class="character_input cloze_input" name="answer[<?= $blank ?>]"
style="width: <?= $exercise->getInputWidth($blank) ?>em;" value="<?= htmlReady($response[$blank] ?? '') ?>"><!--
<? endif ?>
<? endif ?>
<? endforeach ?>
-->
</div>
<? if ($exercise->interactionType() === 'drag'): ?>
<span class="cloze_drop cloze_items math-tex">
<? foreach ($exercise->availableAnswers($solution) as $item): ?>
<span class="cloze_item drag-handle" data-value="<?= htmlReady($item) ?>"><?= htmlReady($item) ?></span>
<? endforeach ?>
</span>
<? endif ?>
<?php
/**
* @var ClozeTask $exercise
* @var float|int $points
*/
?>
<exercise id="exercise-<?= $exercise->id ?>" points="<?= $points ?>"
<? if ($exercise->options['comment']): ?> feedback="true"<? endif ?>>
<title>
<?= htmlReady($exercise->title) ?>
</title>
<description>
<?= htmlReady($exercise->description) ?>
</description>
<? if ($exercise->options['hint'] != ''): ?>
<hint>
<?= htmlReady($exercise->options['hint']) ?>
</hint>
<? endif ?>
<items>
<item type="cloze-<?= $exercise->interactionType() ?>">
<description>
<? foreach (explode('[[]]', $exercise->task['text']) as $blank => $text): ?>
<text><?= htmlReady($text) ?></text>
<? if (isset($exercise->task['answers'][$blank])): ?>
<answers<? if ($exercise->isSelect($blank, false)): ?> select="true"<? endif ?>>
<? foreach ($exercise->task['answers'][$blank] as $answer): ?>
<answer score="<?= $answer['score'] ?>"><?= htmlReady($answer['text']) ?></answer>
<? endforeach ?>
</answers>
<? endif ?>
<? endforeach ?>
</description>
<? if (isset($exercise->task['input_width'])): ?>
<submission-hints>
<input type="text" width="<?= (int) $exercise->task['input_width'] ?>"/>
</submission-hints>
<? endif ?>
<? if (!empty($exercise->task['compare'])): ?>
<evaluation-hints>
<similarity type="<?= htmlReady($exercise->task['compare']) ?>"/>
<? if ($exercise->task['compare'] === 'numeric'): ?>
<input-data type="relative-epsilon">
<?= (float) $exercise->task['epsilon'] ?>
</input-data>
<? endif ?>
</evaluation-hints>
<? endif ?>
<? if ($exercise->options['feedback'] != ''): ?>
<feedback>
<?= htmlReady($exercise->options['feedback']) ?>
</feedback>
<? endif ?>
</item>
</items>
<? if ($exercise->folder): ?>
<file-refs<? if ($exercise->options['files_hidden']): ?> hidden="true"<? endif ?>>
<? foreach ($exercise->folder->file_refs as $file_ref): ?>
<file-ref ref="file-<?= $file_ref->file_id ?>"/>
<? endforeach ?>
</file-refs>
<? endif ?>
</exercise>
<?php
/**
* @var Exercise $exercise
* @var VipsSolution $solution
* @var array $results
* @var array $response
* @var bool $show_solution
*/
?>
<? $exercise->sortAnswersById(); ?>
<table class="default description inline-content">
<thead>
<tr>
<th>
<?= _('Vorgegebener Text') ?>
</th>
<th>
<?= _('Zugeordnete Antworten') ?>
</th>
<? if ($show_solution): ?>
<th>
<?= _('Richtige Antworten') ?>
</th>
<? endif ?>
</tr>
</thead>
<tbody>
<? foreach ($exercise->task['groups'] as $i => $group) : ?>
<tr style="vertical-align: top;">
<td>
<div class="mc_item">
<?= formatReady($group) ?>
</div>
</td>
<td>
<? foreach ($exercise->task['answers'] as $answer): ?>
<? if (isset($response[$answer['id']]) && $response[$answer['id']] == $i): ?>
<div class="<?= $exercise->isCorrectAnswer($answer, $i) ? 'correct_item' : 'mc_item' ?>">
<?= formatReady($answer['text']) ?>
<? if ($exercise->isCorrectAnswer($answer, $i)): ?>
<?= Icon::create('accept', Icon::ROLE_STATUS_GREEN)->asImg(['class' => 'correction_marker', 'title' => _('richtig')]) ?>
<? else: ?>
<?= Icon::create('decline', Icon::ROLE_STATUS_RED)->asImg(['class' => 'correction_marker', 'title' => _('falsch')]) ?>
<? endif ?>
</div>
<? endif ?>
<? endforeach ?>
</td>
<? if ($show_solution): ?>
<td>
<? foreach ($exercise->correctAnswers($i) as $correct_answer): ?>
<div class="correct_item">
<?= formatReady($correct_answer) ?>
</div>
<? endforeach ?>
</td>
<? endif ?>
</tr>
<? endforeach ?>
</tbody>
</table>
<div class="label-text">
<?= _('Nicht zugeordnete Antworten:') ?>
</div>
<? foreach ($exercise->task['answers'] as $answer): ?>
<? if (!isset($response[$answer['id']]) || $response[$answer['id']] == -1): ?>
<div class="inline-block inline-content <?= $exercise->isCorrectAnswer($answer, -1) ? 'correct_item' : 'mc_item' ?>">
<?= formatReady($answer['text']) ?>
<? if ($solution->id): ?>
<? if ($exercise->isCorrectAnswer($answer, -1)): ?>
<?= Icon::create('accept', Icon::ROLE_STATUS_GREEN)->asImg(['class' => 'correction_inline', 'title' => _('richtig')]) ?>
<? else: ?>
<?= Icon::create('decline', Icon::ROLE_STATUS_RED)->asImg(['class' => 'correction_inline', 'title' => _('falsch')]) ?>
<? endif ?>
<? endif ?>
</div>
<? endif ?>
<? endforeach ?>
<?php
/**
* @var ClozeTask $exercise
*/
?>
<label>
<input class="rh_select_type" type="checkbox" name="multiple" value="1" <?= $exercise->isMultiSelect() ? 'checked' : '' ?>>
<?= _('Mehrfachzuordnungen zu einem vorgegebenen Text erlauben') ?>
</label>
<table class="default description <?= $exercise->isMultiSelect() ? '' : 'rh_single' ?>">
<thead>
<tr>
<th style="width: 50%;">
<?= _('Vorgegebener Text') ?>
</th>
<th style="width: 50%;">
<?= _('Zuzuordnende Antworten') ?>
</th>
</tr>
</thead>
<tbody class="dynamic_list" style="vertical-align: top;">
<? foreach ($exercise->task['groups'] as $i => $group): ?>
<? $size = $exercise->flexibleInputSize($group) ?>
<tr class="dynamic_row">
<td class="size_toggle size_<?= $size ?>">
<?= $this->render_partial('exercises/flexible_input', ['name' => "default[$i]", 'value' => $group, 'size' => $size]) ?>
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Zuordnung löschen')]) ?>
</td>
<td class="dynamic_list">
<? $j = 0 ?>
<? foreach ($exercise->task['answers'] as $answer): ?>
<? if ($answer['group'] == $i): ?>
<? $size = $exercise->flexibleInputSize($answer['text']) ?>
<div class="dynamic_row size_toggle size_<?= $size ?>">
<?= $this->render_partial('exercises/flexible_input', ['name' => "answer[$i][$j]", 'value' => $answer['text'], 'size' => $size]) ?>
<input type="hidden" name="id[<?= $i ?>][<?= $j++ ?>]" value="<?= $answer['id'] ?>">
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Antwort löschen')]) ?>
</div>
<? endif ?>
<? endforeach ?>
<div class="dynamic_row size_toggle size_small template">
<?= $this->render_partial('exercises/flexible_input', ['data_name' => "answer[$i]", 'size' => 'small']) ?>
<input type="hidden" data-name="id[<?= $i ?>]">
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Antwort löschen')]) ?>
</div>
<?= Studip\Button::create(_('Antwort hinzufügen'), 'add_answer', ['class' => 'add_dynamic_row rh_add_answer']) ?>
</td>
</tr>
<? endforeach ?>
<tr class="dynamic_row template">
<td class="size_toggle size_small">
<?= $this->render_partial('exercises/flexible_input', ['data_name' => 'default', 'size' => 'small']) ?>
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Zuordnung löschen')]) ?>
</td>
<td class="dynamic_list">
<div class="dynamic_row size_toggle size_small template">
<?= $this->render_partial('exercises/flexible_input', ['data_name' => ':answer', 'size' => 'small']) ?>
<input type="hidden" data-name=":id">
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Antwort löschen')]) ?>
</div>
<?= Studip\Button::create(_('Antwort hinzufügen'), 'add_answer', ['class' => 'add_dynamic_row rh_add_answer']) ?>
</td>
</tr>
<tr>
<th colspan="2">
<?= Studip\Button::create(_('Zuordnung hinzufügen'), 'add_pairs', ['class' => 'add_dynamic_row']) ?>
</th>
</tr>
</tbody>
</table>
<div class="label-text">
<?= _('Distraktoren (optional)') ?>
<?= tooltipIcon(_('Weitere Antworten, die keinem Text zugeordnet werden dürfen.')) ?>
</div>
<div class="dynamic_list">
<? foreach ($exercise->task['answers'] as $answer): ?>
<? if ($answer['group'] == -1): ?>
<? $size = $exercise->flexibleInputSize($answer['text']) ?>
<div class="dynamic_row mc_row">
<label class="dynamic_counter size_toggle size_<?= $size ?> undecorated">
<?= $this->render_partial('exercises/flexible_input', ['name' => '_answer[]', 'value' => $answer['text'], 'size' => $size]) ?>
<input type="hidden" name="_id[]" value="<?= $answer['id'] ?>">
</label>
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Distraktor löschen')]) ?>
</div>
<? endif ?>
<? endforeach ?>
<div class="dynamic_row mc_row template">
<label class="dynamic_counter size_toggle size_small undecorated">
<?= $this->render_partial('exercises/flexible_input', ['data_name' => '', 'name' => '_answer[]', 'size' => 'small']) ?>
<input type="hidden" name="_id[]">
</label>
<?= Icon::create('trash')->asInput(['class' => 'delete_dynamic_row', 'title' => _('Distraktor löschen')]) ?>
</div>
<?= Studip\Button::create(_('Distraktor hinzufügen'), 'add_false_answer', ['class' => 'add_dynamic_row']) ?>
</div>
<?php
/**
* @var ClozeTask $exercise
* @var VipsSolution $solution
* @var bool $print_correction
* @var bool $show_solution
*/
?>
<? $exercise->sortAnswersById(); ?>
<table class="content description inline-content" style="min-width: 40em;">
<thead>
<tr>
<th>
<?= _('Vorgegebener Text') ?>
</th>
<th>
<?= _('Zugeordnete Antworten') ?>
</th>
<? if ($show_solution) : ?>
<th>
<?= _('Richtige Antworten') ?>
</th>
<? endif ?>
</tr>
</thead>
<tbody>
<? foreach ($exercise->task['groups'] as $i => $group) : ?>
<tr style="vertical-align: top;">
<td>
<div class="mc_item">
<?= formatReady($group) ?>
</div>
</td>
<td>
<? foreach ($exercise->task['answers'] as $answer): ?>
<? if (isset($response[$answer['id']]) && $response[$answer['id']] == $i): ?>
<div class="<?= $print_correction && $exercise->isCorrectAnswer($answer, $i) ? 'correct_item' : 'mc_item' ?>">
<?= formatReady($answer['text']) ?>
<? if ($print_correction): ?>
<? if ($exercise->isCorrectAnswer($answer, $i)) : ?>
<?= Icon::create('accept', Icon::ROLE_STATUS_GREEN)->asImg(['class' => 'correction_marker', 'title' => _('richtig')]) ?>
<? else : ?>
<?= Icon::create('decline', Icon::ROLE_STATUS_RED)->asImg(['class' => 'correction_marker', 'title' => _('falsch')]) ?>
<? endif ?>
<? endif ?>
</div>
<? endif ?>
<? endforeach ?>
</td>
<? if ($show_solution) : ?>
<td>
<? foreach ($exercise->correctAnswers($i) as $correct_answer): ?>
<div class="mc_item">
<?= formatReady($correct_answer) ?>
</div>
<? endforeach ?>
</td>
<? endif ?>
</tr>
<? endforeach ?>
</tbody>
</table>
<div class="label-text">
<? if ($print_correction): ?>
<?= _('Nicht zugeordnete Antworten:') ?>
<? else: ?>
<?= _('Antwortmöglichkeiten:') ?>
<? endif ?>
</div>
<ol class="inline-content">
<? foreach ($exercise->task['answers'] as $answer): ?>
<? if (!isset($response[$answer['id']]) || $response[$answer['id']] == -1): ?>
<li>
<?= formatReady($answer['text']) ?>
<? if ($solution->id && $print_correction): ?>
<? if ($exercise->isCorrectAnswer($answer, -1)): ?>
<?= Icon::create('accept', Icon::ROLE_STATUS_GREEN)->asImg(['title' => _('richtig')]) ?>
<? else: ?>
<?= Icon::create('decline', Icon::ROLE_STATUS_RED)->asImg(['title' => _('falsch')]) ?>
<? endif ?>
<? endif ?>
</li>
<? endif ?>
<? endforeach ?>
</ol>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment