Skip to content
Snippets Groups Projects
Commit 502e6a10 authored by Michaela Brückner's avatar Michaela Brückner :unicorn:
Browse files

new registry formular, re #1559

Closes #3533

Merge request studip/studip!1141
parent b6bdba58
No related branches found
No related tags found
No related merge requests found
Showing
with 505 additions and 167 deletions
<?php
class RegistrationController extends AuthenticatedController
{
protected $allow_nobody = true;
public function before_filter(&$action, &$args)
{
parent::before_filter($action, $args);
PageLayout::setTitle(_('Registrierung'));
}
public function index_action()
{
$new_user = new User();
$this->registrationform = \Studip\Forms\Form::fromSORM(
$new_user,
[
'legend' => _('Herzlich willkommen!'),
'fields' => [
'username' => [
'label' => _('Benutzername'),
'required' => true,
'maxlength' => '63',
'validate' => function ($value, $input) {
if (!preg_match(Config::get()->USERNAME_REGULAR_EXPRESSION, $value)) {
return Config::get()->getMetadata('USERNAME_REGULAR_EXPRESSION')['comment'] ?:
_('Benutzername muss mindestens 4 Zeichen lang sein und darf nur aus Buchstaben, '
. 'Ziffern, Unterstrich, @, Punkt und Minus bestehen.');
}
$user = User::findByUsername($value);
$context = $input->getContextObject();
if ($user && ($user->id !== $context->getId())) {
return _('Benutzername ist schon vergeben.');
}
return true;
}
],
'password' => [
'label' => _('Passwort'),
'type' => 'password',
'required' => true,
'maxlength' => '31',
'minlength' => '8',
'mapper' => function($value) {
$hasher = UserManagement::getPwdHasher();
return $hasher->HashPassword($value);
}
],
'confirm_password' => [
'label' => _('Passwortbestätigung'),
'type' => 'password',
'required' => true,
'maxlength' => '31',
'minlength' => '8',
':pattern' => "password.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&')", //mask special chars
'data-validation_requirement' => _('Passwörter stimmen nicht überein.'),
'store' => function() {}
],
'title_front' => [
'label' => _('Titel'),
'type' => 'datalist',
'options' => $GLOBALS['TITLE_FRONT_TEMPLATE']
],
'title_rear' => [
'label' => _('Titel nachgestellt'),
'type' => 'datalist',
'options' => $GLOBALS['TITLE_REAR_TEMPLATE'],
],
'vorname' => [
'label' => _('Vorname'),
'required' => true
],
'nachname' => [
'label' => _('Nachname'),
'required' => true
],
'geschlecht' => [
'name' => 'geschlecht',
'label' => _('Geschlecht'),
'type' => 'radio',
'orientation' => 'horizontal',
'options' => [
'0' => _('keine Angabe'),
'1' => _('männlich'),
'2' => _('weiblich'),
'3' => _('divers'),
],
],
'email' => [
'label' => _('E-Mail'),
'required' => true,
'validate' => function ($value, $input) {
$user = User::findOneByEmail($value);
$context = $input->getContextObject();
if ($user && ($user->id !== $context->getId())) {
return _('Diese Emailadresse ist bereits registriert.');
}
return true;
}
],
]
]
);
$this->registrationform->setSaveButtonText(_('Registrierung abschließen'));
$this->registrationform->setCancelButtonText(_('Abbrechen'));
$this->registrationform->setCancelButtonName(URLHelper::getURL('index.php?cancel_login=1'));
$this->registrationform->addStoreCallback(
function ($form) {
$new_user = $form->getLastPart()->getContextObject();
$GLOBALS['sess']->regenerate_session_id(['auth']);
$GLOBALS['auth']->unauth();
$GLOBALS['auth']->auth['jscript'] = true;
$GLOBALS['auth']->auth['perm'] = $new_user['perms'];
$GLOBALS['auth']->auth['uname'] = $new_user['username'];
$GLOBALS['auth']->auth['auth_plugin'] = $new_user['auth_plugin'];
$GLOBALS['auth']->auth_set_user_settings($new_user->user_id);
$GLOBALS['auth']->auth['uid'] = $new_user['user_id'];
$GLOBALS['auth']->auth['exp'] = time() + (60 * $GLOBALS['auth']->lifetime);
$GLOBALS['auth']->auth['refresh'] = time() + (60 * $GLOBALS['auth']->refresh);
Seminar_Register_Auth::sendValidationMail($new_user);
return 1;
}
);
$this->registrationform->autoStore()->setURL(URLHelper::getURL('dispatch.php/start'));
}
}
<?= $registrationform->render() ?>
File moved
<?php
class UpdateUsernameRegularExpression extends Migration
{
public function description()
{
return 'Alters configuration description to make clearer that it is used for creating new users';
}
public function up()
{
$db = DBManager::get();
$stmt = $db->prepare("UPDATE `config`
SET `description` = 'Regulärer Ausdruck für erlaubte Zeichen in Benutzernamen. Das Kommentarfeld kann genutzt werden, um eine Fehlermeldung anzugeben, die zum Beispiel im Registrierungsformular ausgegeben wird, wenn der Ausdruck nicht erfüllt wird.'
WHERE `field` = 'USERNAME_REGULAR_EXPRESSION'");
$stmt->execute();
}
public function down()
{
$db = DBManager::get();
$stmt = $db->prepare("UPDATE `config`
SET `description` = 'Regex for allowed characters in usernames'
WHERE `field` = 'USERNAME_REGULAR_EXPRESSION'");
$stmt->execute();
}
}
<?php
namespace Studip\Forms;
class ConfirmInput extends Input
{
public function render()
{
$template = $GLOBALS['template_factory']->open('forms/confirm_password_input');
$template->title = $this->title;
$template->name = $this->name;
$template->value = $this->value;
$template->id = md5(uniqid());
$template->required = $this->required;
$template->attributes = arrayToHtmlAttributes($this->attributes);
return $template->render();
}
}
<?php
namespace Studip\Forms;
class DatalistInput extends Input
{
public function render()
{
$options = $this->extractOptionsFromAttributes($this->attributes);
$template = $GLOBALS['template_factory']->open('forms/datalist_input');
$template->title = $this->title;
$template->name = $this->name;
$template->value = $this->value;
$template->id = md5(uniqid());
$template->required = $this->required;
$template->attributes = arrayToHtmlAttributes($this->attributes);
$template->options = $options;
return $template->render();
}
}
......@@ -17,6 +17,8 @@ class Form extends Part
protected $save_button_text = '';
protected $save_button_name = '';
protected $cancel_button_text = '';
protected $cancel_button_name = '';
protected $autoStore = false;
protected $debugmode = false;
protected $success_message = '';
......@@ -207,6 +209,31 @@ class Form extends Part
return $this->save_button_name ?: $this->getSaveButtonText();
}
public function setCancelButtonText(string $text): Form
{
$this->cancel_button_text = $text;
return $this;
}
/**
* @return string The text for the "save" button in the form.
*/
public function getCancelButtonText() : string
{
return $this->cancel_button_text ?: _('Abbrechen');
}
public function setCancelButtonName(string $name): Form
{
$this->cancel_button_name = $name;
return $this;
}
public function getCancelButtonName() : string
{
return $this->cancel_button_name ?: $this->getCancelButtonText();
}
public function setSuccessMessage(string $success_message): Form
{
$this->success_message = $success_message;
......@@ -250,12 +277,35 @@ class Form extends Part
{
$this->autoStore = true;
if (\Request::isPost() && \Request::isAjax() && !\Request::isDialog()) {
$this->store();
if ($this->success_message) {
\PageLayout::postSuccess($this->success_message);
if (\Request::submitted('STUDIPFORM_SERVERVALIDATION')) {
//verify the user input:
$output = [];
foreach ($this->getAllInputs() as $input) {
if ($input->validate) {
$callback = $input->getValidationCallback();
$value = $this->getStorableValueFromRequest($input);
$valid = $callback($value, $input);
if ($valid !== true) {
$output[$input->getName()] = [
'name' => $input->getName(),
'label' => $input->getTitle(),
'error' => $callback($value, $input)
];
}
}
}
echo json_encode($output);
page_close();
die();
} else {
//storing the input
$this->store();
if ($this->success_message) {
\PageLayout::postSuccess($this->success_message);
}
page_close();
die();
}
page_close();
die();
}
return $this;
}
......@@ -325,6 +375,17 @@ class Form extends Part
$stored = 0;
foreach ($this->getAllInputs() as $input) {
if ($input->validate) {
$callback = $input->getValidationCallback();
$value = $this->getStorableValueFromRequest($input);
$valid = $callback($value, $input);
if ($valid !== true) {
return $stored;
}
}
}
//store by each input
$all_values = [];
foreach ($this->getAllInputs() as $input) {
......
......@@ -11,6 +11,7 @@ abstract class Input
protected $parent = null;
public $mapper = null;
public $store = null;
public $validate = null;
public $if = null;
public $permission = true;
public $required = false;
......@@ -133,6 +134,21 @@ abstract class Input
return $this->name;
}
public function getTitle()
{
return $this->title;
}
public function hasValidation()
{
return $this->validate !== null;
}
public function getValidationCallback()
{
return $this->validate;
}
/**
* Returns the value of this input.
* @return null
......@@ -215,6 +231,18 @@ abstract class Input
return $this;
}
/**
* Sets the server-side verify function of this input. The callable returns true if the given value is okay, or
* false or a textstring representing the error.
* @param callable $verify
* @return $this
*/
public function setValidationFunction(Callable $validate)
{
$this->validate = $validate;
return $this;
}
/**
* Sets a condition to display this input. The condition is a javascript condition which is used by vue to
* hide the input if the condition is not satisfies.
......@@ -261,7 +289,7 @@ abstract class Input
protected function extractOptionsFromAttributes(array &$attributes)
{
$options = null;
$options = [];
if (isset($attributes['options'])) {
$options = $attributes['options'];
unset($attributes['options']);
......
......@@ -235,6 +235,7 @@ abstract class Part
$attributes['type'],
$attributes['mapper'],
$attributes['store'],
$attributes['validate'],
$attributes['if'],
$attributes['permission'],
$attributes['required'],
......@@ -257,6 +258,9 @@ abstract class Part
if (isset($data['store']) && is_callable($data['store'])) {
$input->store = $data['store'];
}
if (isset($data['validate']) && is_callable($data['validate'])) {
$input->validate = $data['validate'];
}
if (!empty($data['if'])) {
$input->if = $data['if'];
}
......
<?php
namespace Studip\Forms;
class PasswordInput extends Input
{
public function render()
{
$template = $GLOBALS['template_factory']->open('forms/password_input');
$template->title = $this->title;
$template->name = $this->name;
$template->value = $this->value;
$template->id = md5(uniqid());
$template->required = $this->required;
$template->attributes = arrayToHtmlAttributes($this->attributes);
return $template->render();
}
}
<?php
namespace Studip\Forms;
class RadioInput extends Input
{
public function render()
{
$options = $this->extractOptionsFromAttributes($this->attributes);
$template = $GLOBALS['template_factory']->open('forms/radio_input');
$template->title = $this->title;
$template->name = $this->name;
$template->value = $this->value;
$template->id = md5(uniqid());
$template->required = $this->required;
$template->options = $options;
$template->attributes = arrayToHtmlAttributes($this->attributes);
$template->orientation = $this->attributes['orientation'];
return $template->render();
}
}
......@@ -11,6 +11,9 @@ class RangeInput extends Input
$template->name = $this->name;
$template->value = $this->value;
$template->id = md5(uniqid());
$template->min = $this->attributes['min'];
$template->max = $this->attributes['max'];
$template->step = $this->attributes['step'];
$template->required = $this->required;
$template->attributes = arrayToHtmlAttributes($this->attributes);
return $template->render();
......
......@@ -43,9 +43,9 @@ class LoginNavigation extends Navigation
}
if (Config::get()->ENABLE_SELF_REGISTRATION) {
$navigation = new Navigation(_('Registrieren'), 'register1.php');
$navigation = new Navigation(_('Registrieren'), 'dispatch.php/registration');
$navigation->setDescription(_('um das System erstmalig zu nutzen'));
$this->addSubNavigation('register', $navigation);
$this->addSubNavigation('registration', $navigation);
}
if (Config::get()->ENABLE_FREE_ACCESS) {
......
<?php
/**
* register1.php - Benutzerregistrierung in Stud.IP, Part I
*
* @author Stefan Suchi <suchi@gmx.de>
* @author Oliver Brakel <obrakel@gwdg.de>
* @copyright 2000 authors
* @license GPL2 or any later version
*/
require '../lib/bootstrap.php';
page_open([
'sess' => 'Seminar_Session',
'auth' => 'Seminar_Default_Auth',
'perm' => 'Seminar_Perm',
'user' => 'Seminar_User',
]);
include 'lib/seminar_open.php'; // initialise Stud.IP-Session
if (!Config::get()->ENABLE_SELF_REGISTRATION) {
PageLayout::postError(_('Registrierung ausgeschaltet'), [
_('In dieser Installation ist die Möglichkeit zur Registrierung ausgeschaltet.'),
sprintf(
'<a href="%s">%s</a>',
URLHelper::getLink('index.php'),
_('Hier geht es zur Startseite.')
)
]);
echo $GLOBALS['template_factory']->render('layouts/base.php', [
'content_for_layout' => '',
]);
} elseif (Config::get()->SHOW_TERMS_ON_FIRST_LOGIN) {
header('Location: ' . URLHelper::getURL('register2.php'));
} elseif ($GLOBALS['auth']->is_authenticated() && $GLOBALS['user']->id !== 'nobody') {
PageLayout::postError(_('Sie sind schon als BenutzerIn am System angemeldet!'), [
sprintf(
'<a href="%s">%s</a>',
URLHelper::getLink('index.php'),
_('Hier geht es zur Startseite.')
)
]);
echo $GLOBALS['template_factory']->render('layouts/base.php', [
'content_for_layout' => '',
]);
} else {
PageLayout::setHelpKeyword('Basis.AnmeldungRegistrierung');
PageLayout::setTitle(_('Nutzungsbedingungen'));
echo $GLOBALS['template_factory']->render(
'register/step1.php',
[],
$GLOBALS['template_factory']->open('layouts/base.php')
);
$auth->logout();
}
page_close();
<?php
/**
* register2.php - Benutzerregistrierung in Stud.IP, Part II
*
* @author Stefan Suchi <suchi@gmx.de>
* @author Oliver Brakel <obrakel@gwdg.de>
* @copyright 2000 authors
* @license GPL2 or any later version
*/
require '../lib/bootstrap.php';
page_open([
'sess' => 'Seminar_Session',
'auth' => Config::get()->ENABLE_SELF_REGISTRATION ? 'Seminar_Register_Auth' : 'Seminar_Default_Auth',
'perm' => 'Seminar_Perm',
'user' => 'Seminar_User',
]);
if (!Config::get()->ENABLE_SELF_REGISTRATION){
PageLayout::postError(_('Registrierung ausgeschaltet'), [
_('In dieser Installation ist die Möglichkeit zur Registrierung ausgeschaltet.'),
sprintf(
'<a href="%s">%s</a>',
URLHelper::getLink('index.php'),
_('Hier geht es zur Startseite.')
)
]);
echo $GLOBALS['template_factory']->render('layouts/base.php', [
'content_for_layout' => '',
]);
} elseif ($GLOBALS['auth']->auth['uid'] === 'nobody') {
$GLOBALS['auth']->logout();
header('Location: ' . URLHelper::getURL('register2.php'));
} else {
include 'lib/seminar_open.php'; // initialise Stud.IP-Session
PageLayout::setHelpKeyword('Basis.AnmeldungRegistrierung');
PageLayout::setTitle(_('Registrierung erfolgreich'));
echo $GLOBALS['template_factory']->render(
'register/success.php',
[],
$GLOBALS['template_factory']->open('layouts/base.php')
);
$GLOBALS['auth']->logout();
}
page_close();
......@@ -250,12 +250,15 @@ STUDIP.ready(function () {
data() {
let params = JSON.parse(f.dataset.inputs);
params.STUDIPFORM_REQUIRED = f.dataset.required ? JSON.parse(f.dataset.required) : [];
params.STUDIPFORM_SERVERVALIDATION = f.dataset.server_validation > 0;
params.STUDIPFORM_DISPLAYVALIDATION = false;
params.STUDIPFORM_VALIDATIONNOTES = [];
params.STUDIPFORM_AUTOSAVEURL = f.dataset.autosave;
params.STUDIPFORM_REDIRECTURL = f.dataset.url;
params.STUDIPFORM_SELECTEDLANGUAGES = {};
params.STUDIPFORM_DEBUGMODE = JSON.parse(f.dataset.debugmode);
params.STUDIPFORM_INPUTS_ORDER = [];
for (let i in JSON.parse(f.dataset.inputs)) {
params.STUDIPFORM_INPUTS_ORDER.push(i);
}
return params;
},
methods: {
......@@ -265,31 +268,31 @@ STUDIP.ready(function () {
this.STUDIPFORM_DISPLAYVALIDATION = true;
//validation:
let validated = this.validate();
if (!validated) {
e.preventDefault();
v.$el.scrollIntoView({
"behavior": "smooth"
});
return;
}
if (this.STUDIPFORM_AUTOSAVEURL) {
let params = this.getFormValues();
let validation_promise = this.validate();
validation_promise.then(function (validated) {
if (!validated) {
v.$el.scrollIntoView({
behavior: 'smooth'
});
return;
}
$.ajax({
url: this.STUDIPFORM_AUTOSAVEURL,
data: params,
type: 'post',
success() {
if (v.STUDIPFORM_REDIRECTURL && !v.STUDIPFORM_DEBUGMODE) {
window.location.href = v.STUDIPFORM_REDIRECTURL;
if (v.STUDIPFORM_AUTOSAVEURL) {
let params = v.getFormValues();
$.ajax({
url: v.STUDIPFORM_AUTOSAVEURL,
data: params,
type: 'post',
success() {
if (v.STUDIPFORM_REDIRECTURL) {
window.location.href = v.STUDIPFORM_REDIRECTURL
}
}
}
});
e.preventDefault();
}
});
}
});
e.preventDefault();
},
getFormValues() {
let v = this;
......@@ -311,32 +314,74 @@ STUDIP.ready(function () {
let v = this;
this.STUDIPFORM_VALIDATIONNOTES = [];
let validated = this.$el.checkValidity();
$(this.$el).find('input, select, textarea').each(function () {
if (!this.validity.valid) {
let note = {
name: $(this.labels[0]).find('.textlabel').text(),
description: $gettext('Fehler!'),
describedby: this.id
};
if (this.validity.tooShort) {
note.description = $gettextInterpolate(
$gettext('Geben Sie mindestens %{min} Zeichen ein.'),
{min: this.minLength}
);
}
if (this.validity.valueMissing) {
if (this.type === 'checkbox') {
note.description = $gettext('Dieses Feld muss ausgewählt sein.');
} else {
note.description = $gettext('Hier muss ein Wert eingetragen werden.');
let validation_promise = new Promise(function (resolve, reject) {
let validated = v.$el.checkValidity();
$(v.$el).find('input, select, textarea').each(function () {
let name = $(this).attr('name');
if (!this.validity.valid) {
let note = {
name: this.name,
label: $(this.labels[0]).find('.textlabel').text(),
description: $gettext('Fehler!'),
describedby: this.id
};
if ($(this).data('validation_requirement')) {
note.description = $(this).data('validation_requirement');
}
if (this.validity.tooShort) {
note.description = $gettextInterpolate(
$gettext('Geben Sie mindestens %{min} Zeichen ein.'),
{min: this.minLength}
);
}
if (this.validity.valueMissing) {
if (this.type === 'checkbox') {
note.description = $gettext('Dieses Feld muss ausgewählt sein.');
} else {
if (this.minLength > 0) {
note.description = $gettextInterpolate(
$gettext('Hier muss ein Wert mit mindestens %{min} Zeichen eingetragen werden.'),
{min: this.minLength}
);
} else {
note.description = $gettext('Hier muss ein Wert eingetragen werden.');
}
}
}
v.STUDIPFORM_VALIDATIONNOTES.push(note);
}
v.STUDIPFORM_VALIDATIONNOTES.push(note);
});
if (v.STUDIPFORM_SERVERVALIDATION) {
let params = v.getFormValues();
params.STUDIPFORM_SERVERVALIDATION = 1;
$.ajax({
url: v.STUDIPFORM_AUTOSAVEURL,
data: params,
type: 'post',
dataType: 'json',
success(output) {
for (let i in output) {
let note = {
name: output[i].name,
label: output[i].label,
description: output[i].error,
describedby: null
};
v.STUDIPFORM_VALIDATIONNOTES.push(note);
}
validated = v.STUDIPFORM_VALIDATIONNOTES.length < 1;
resolve(validated);
}
});
} else {
resolve(validated);
}
});
return validated;
return validation_promise;
},
setInputs(inputs) {
for (const [key, value] of Object.entries(inputs)) {
......@@ -353,6 +398,19 @@ STUDIP.ready(function () {
this.STUDIPFORM_SELECTEDLANGUAGES = languages;
}
},
computed: {
ordererValidationNotes: function () {
let orderedNotes = [];
for (let i in this.STUDIPFORM_INPUTS_ORDER) {
for (let k in this.STUDIPFORM_VALIDATIONNOTES) {
if (this.STUDIPFORM_VALIDATIONNOTES[k].name === this.STUDIPFORM_INPUTS_ORDER[i]) {
orderedNotes.push(this.STUDIPFORM_VALIDATIONNOTES[k]);
}
}
}
return orderedNotes;
}
},
mounted () {
$(this.$el).addClass("vueified");
}
......@@ -362,7 +420,7 @@ STUDIP.ready(function () {
}
// Well, this is really nasty: Select2 can't determine the select
// element's width if it is hidden (by itself or by it's parent).
// element's width if it is hidden (by itself or by its parent).
// This is due to the fact that elements are not rendered when hidden
// (which seems pretty obvious when you think about it) but elements
// only have a width when they are rendered (pretty obvious as well).
......
......@@ -70,6 +70,14 @@ form.default {
}
}
input[list] {
@include background-icon(arr_1down, clickable);
background-repeat: no-repeat;
background-position: center right 4px;
padding-right: 24px
}
textarea:not(.size-l) + .ck-editor {
max-width: $max-width-m;
}
......
<div class="formpart">
<label <?= $this->required ? 'class="studiprequired"' : '' ?> for="<?= $id ?>">
<span class="textlabel">
<?= htmlReady($this->title) ?>
</span>
<? if ($this->required) : ?>
<span class="asterisk" title="<?= _('Dies ist ein Pflichtfeld') ?>" aria-hidden="true">*</span>
<? endif ?>
<input type="password"
v-model="<?= htmlReady($this->name) ?>"
name="<?= htmlReady($this->name) ?>"
value="<?= htmlReady($this->value) ?>"
id="<?= $id ?>" <?= $this->required ? 'required aria-required="true"' : '' ?>
<?= $attributes ?>>
</label>
</div>
<div class="formpart">
<label <?= $this->required ? 'class="studiprequired"' : '' ?> for="<?= $id ?>">
<span class="textlabel">
<?= htmlReady($this->title) ?>
</span>
<? if ($this->required) : ?>
<span class="asterisk" title="<?= _('Dies ist ein Pflichtfeld') ?>" aria-hidden="true">*</span>
<? endif ?>
<input type="text" list="<?= $this->title ?>" id="" v-model="<?= htmlReady($this->name) ?>" <?= $this->required ? 'required aria-required="true"' : '' ?> />
<datalist class="" id="<?= $this->title ?>" <?= $attributes ?>>
<? foreach ($options as $key => $option) : ?>
<option value="<?= htmlReady($option) ?>"<?= ($option == $value ? " selected" : "") ?>>
</option>
<? endforeach ?>
</datalist>
</label>
</div>
......@@ -2,14 +2,17 @@
$inputs = [];
$allinputs = $form->getAllInputs();
$required_inputs = [];
$server_validation = false;
foreach ($allinputs as $input) {
foreach ($input->getAllInputNames() as $name) {
$inputs[$name] = $input->getValue();
}
if ($input->required) {
$required_inputs[] = $input->getName();
}
if ($input->hasValidation()) {
$server_validation = true;
}
}
$form_id = md5(uniqid());
?><form v-cloak
......@@ -21,12 +24,14 @@ $form_id = md5(uniqid());
data-url="<?= htmlReady($form->getURL()) ?>"
<? endif ?>
@submit="submit"
@cancel=""
novalidate
<?= $form->getDataSecure() ? 'data-secure' : '' ?>
id="<?= htmlReady($form_id) ?>"
data-inputs="<?= htmlReady(json_encode($inputs)) ?>"
data-debugmode="<?= htmlReady(json_encode($form->getDebugMode())) ?>"
data-required="<?= htmlReady(json_encode($required_inputs)) ?>"
data-server_validation="<?= $server_validation ? 1 : 0?>"
class="default studipform<?= $form->isCollapsable() ? ' collapsable' : '' ?>">
<?= CSRFProtection::tokenTag(['ref' => 'securityToken']) ?>
......@@ -52,7 +57,7 @@ $form_id = md5(uniqid());
<div v-if="STUDIPFORM_DISPLAYVALIDATION && (STUDIPFORM_VALIDATIONNOTES.length > 0)">
<?= _('Folgende Angaben müssen korrigiert werden, um das Formular abschicken zu können:') ?>
<ul>
<li v-for="note in STUDIPFORM_VALIDATIONNOTES" :aria-describedby="note.describedby">{{ note.name + ": " + note.description }}</li>
<li v-for="note in ordererValidationNotes" :aria-describedby="note.describedby">{{ note.label.trim() + ": " + note.description }}</li>
</ul>
</div>
</article>
......@@ -64,7 +69,8 @@ $form_id = md5(uniqid());
</div>
<? if (!Request::isDialog()) : ?>
<footer>
<?= \Studip\Button::create($form->getSaveButtonText(), $form->getSaveButtonName(), ['form' => $form_id]) ?>
<?= \Studip\Button::createAccept($form->getSaveButtonText(), $form->getSaveButtonName(), ['form' => $form_id]) ?>
<?= \Studip\LinkButton::createCancel($form->getCancelButtonText(), $form->getCancelButtonName()) ?>
</footer>
<? endif ?>
</form>
......
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