Skip to content
Snippets Groups Projects
Commit fb0acb3e authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms Committed by David Siegfried
Browse files

introduce vue directive v-autofocus, fixes #3986

Closes #3986

Merge request studip/studip!2836
parent 4012408c
No related branches found
No related tags found
No related merge requests found
......@@ -50,3 +50,158 @@ $questionnaire_data = [
'range-id' => Request::get('range_id'),
'range-type' => Request::get('range_type'),
]) ?>
=======
<form action="<?= URLHelper::getLink('dispatch.php/questionnaire/edit/' . (!$questionnaire->isNew() ? $questionnaire->getId() : '')) ?>"
method="post"
enctype="multipart/form-data"
class="questionnaire_edit default"
data-questiontypes="<?= htmlReady(json_encode($questiontypes)) ?>"
data-questionnaire_data="<?= htmlReady(json_encode($questionnaire_data)) ?>"
data-questions_data="<?= htmlReady(json_encode($questions_data)) ?>"
data-range_type="<?= htmlReady(Request::get('range_type')) ?>"
data-range_id="<?= htmlReady(Request::get('range_id')) ?>"
<?= Request::isAjax() ? 'data-dialog' : '' ?>
:data-secure="activateFormSecure">
<div class="editor">
<div class="rightside" aria-live="polite" tabindex="0" ref="rightside">
<div class="admin" v-if="activeTab === 'admin'">
<article aria-live="assertive" class="validation_notes studip">
<header>
<h1>
<?= Icon::create('info-circle', Icon::ROLE_INFO)->asImg(['class' => 'text-bottom validation_notes_icon']) ?>
<?= _('Hinweise zum Ausfüllen des Formulars') ?>
</h1>
</header>
<div class="required_note">
<div aria-hidden="true">
<?= _('Pflichtfelder sind mit Sternchen gekennzeichnet.') ?>
</div>
<div class="sr-only">
<?= _('Dieses Formular enthält Pflichtfelder.') ?>
</div>
</div>
<div v-if="validationNotice && !data.title">
<?= _('Folgende Angaben müssen korrigiert werden, um das Formular abschicken zu können:') ?>
<ul>
<li aria-describedby="questionnaire_title"><?= _('Titel des Fragebogens') ?></li>
</ul>
</div>
</article>
<div class="formpart">
<label class="studiprequired" for="questionnaire_title">
<span class="textlabel"><?= _('Titel des Fragebogens') ?></span>
<span title="Dies ist ein Pflichtfeld" aria-hidden="true" class="asterisk">*</span>
</label>
<input type="text" id="questionnaire_title" v-model="data.title" v-autofocus>
</div>
<div class="hgroup">
<label>
<?= _('Startzeitpunkt') ?>
<datetimepicker v-model="data.startdate"></datetimepicker>
</label>
<label>
<?= _('Endzeitpunkt') ?>
<datetimepicker v-model="data.stopdate"></datetimepicker>
</label>
</div>
<label>
<input type="checkbox" v-model="data.copyable" true-value="1" false-value="0">
<?= _('Fragebogen zum Kopieren freigeben') ?>
</label>
<label>
<input type="checkbox" v-model="data.anonymous" true-value="1" false-value="0">
<?= _('Teilnehmende anonymisieren') ?>
</label>
<label>
<input type="checkbox" v-model="data.editanswers" true-value="1" false-value="0">
<?= _('Teilnehmende dürfen ihre Antworten revidieren') ?>
</label>
<label>
<?= _('Ergebnisse einsehbar') ?>
<select v-model="data.resultvisibility">
<option value="always"><?= _('Immer') ?></option>
<option value="afterending"><?= _('Nach Ende der Befragung') ?></option>
<option value="afterparticipation"><?= _('Nach der Teilnahme') ?></option>
<option value="never"><?= _('Niemals') ?></option>
</select>
</label>
</div>
<div class="add_question file_select_possibilities" v-else-if="activeTab === 'add_question'">
<div>
<button v-for="(questiontype, key) in questiontypes" :key="key"
:ref="key == Object.keys(questiontypes)[0] ? 'autofocus' : ''"
href=""
@click.prevent="addQuestion(questiontype.type)">
<studip-icon :shape="questiontype.icon" :size="40"></studip-icon>
{{questiontype.name}}
</button>
</div>
</div>
<div v-else>
<component :is="questiontypes[questions[indexForQuestion].questiontype].component[0]"
v-model="questions[indexForQuestion].questiondata"
:question_id="questions[indexForQuestion].id"
:key="questions[indexForQuestion].id">
</component>
</div>
</div>
<aside>
<a class="admin"
:class="{active: activeTab === 'admin'}"
href="#"
@click.prevent="switchTab('admin')">
<span class="icon"><studip-icon shape="evaluation" :size="30" alt=""></studip-icon></span>
<?= _('Einstellungen') ?>
</a>
<draggable v-if="questions.length > 0" v-model="questions" handle=".drag-handle" group="questions" class="questions_container questions">
<div v-for="question in questions"
:key="question.id"
@mouseenter="hoverTab = question.id"
@mouseleave="hoverTab = null"
:class="(activeTab === question.id || activeTab === 'meta_' + question.id ? 'active' : '') + (hoverTab === question.id ? ' hovered' : '')">
<a href="#"
@click.prevent="switchTab(question.id)">
<span class="drag-handle"></span>
<span class="icon type">
<studip-icon :shape="questiontypes[question.questiontype].icon" :size="30" alt=""></studip-icon>
</span>
<div v-if="editInternalName !== question.id">{{ question.internal_name || questiontypes[question.questiontype].name}}</div>
<div v-else class="inline_editing">
<input type="text" ref="editInternalName" v-model="tempInternalName" class="inlineediting_internal_name">
<button @click="saveInternalName(question.id)">
<studip-icon shape="accept" :size="20" title="<?= _('Internen Namen speichern') ?>"></studip-icon>
</button>
<button @click="editInternalName = null">
<studip-icon shape="decline" :size="20" title="<?= _('Internen Namen nicht speichern') ?>"></studip-icon>
</button>
</div>
</a>
<studip-action-menu :items="[{label: '<?= _('Umbenennen') ?>', icon: 'edit', emit: 'rename'}, {label: '<?= _('Frage kopieren') ?>', icon: 'copy', emit: 'copy'}, {label: '<?= _('Frage nach oben verschieben') ?>', icon: 'arr_1up', emit: 'moveup'}, {label: '<?= _('Frage nach unten verschieben') ?>', icon: 'arr_1down', emit: 'movedown'}, {label: '<?= _('Frage löschen') ?>', icon: 'trash', emit: 'delete'}]"
@copy="duplicateQuestion(question.id)"
@rename="renameInternalName(question.id)"
@moveup="moveQuestionUp(question.id)"
@movedown="moveQuestionDown(question.id)"
@delete="deleteQuestion(question.id)"></studip-action-menu>
</div>
</draggable>
<a :class="activeTab === 'add_question' ? 'add_question active' : 'add_question'"
href="#"
@click.prevent="switchTab('add_question')">
<span class="icon"><studip-icon shape="add" :size="30" alt=""></studip-icon></span>
<?= _('Element hinzufügen') ?>
</a>
</aside>
</div>
<footer data-dialog-button>
<?= Studip\LinkButton::create(_('Speichern'), 'questionnaire_store', ['onclick' => 'STUDIP.Questionnaire.Editor.submit(); return false;']) ?>
</footer>
</form>
>>>>>>> 166e475f04 (introduce vue directive v-autofocus, fixes #3986)
import autofocus from './directives/autofocus';
const BaseDirectives = {
autofocus,
};
export default BaseDirectives;
<template>
<div>
<div class="formpart" tabindex="0" ref="autofocus">
<div class="formpart" tabindex="0">
{{ $gettext('Frage') }}
<StudipWysiwyg v-model="val_clone.description" />
</div>
......@@ -23,9 +23,6 @@ export default {
description: '',
mandatory: '0',
});
},
mounted() {
this.$refs.autofocus.focus();
}
}
</script>
<template>
<div class="likert_edit">
<div class="formpart" tabindex="0" ref="autofocus">
<div class="formpart" tabindex="0">
{{ $gettext('Einleitungstext' )}}
<StudipWysiwyg v-model="val_clone.description" />
</div>
......@@ -65,9 +66,6 @@ export default {
mixins: [ QuestionnaireComponent ],
created() {
this.setDefaultValues(default_values());
},
mounted() {
this.$refs.autofocus.focus();
}
}
</script>
......@@ -39,7 +39,7 @@
<span class="textlabel">{{ $gettext('Titel des Fragebogens') }}</span>
<span title="Dies ist ein Pflichtfeld" aria-hidden="true" class="asterisk">*</span>
</label>
<input type="text" id="questionnaire_title" v-model="data.title" ref="autofocus">
<input type="text" id="questionnaire_title" v-model="data.title" v-autofocus>
</div>
<div class="hgroup">
......@@ -77,7 +77,6 @@
<div class="add_question file_select_possibilities" v-else-if="activeTab === 'add_question'">
<div>
<button v-for="(questiontype, key) in questionTypes" :key="key"
:ref="key == Object.keys(questionTypes)[0] ? 'autofocus' : ''"
href=""
@click.prevent="addQuestion(questiontype.type)"
>
......@@ -283,17 +282,6 @@ export default {
},
switchTab(tab_id) {
this.activeTab = tab_id;
this.$nextTick(function () {
if (this.$refs.autofocus !== undefined) {
if (Array.isArray(this.$refs.autofocus)) {
if (typeof this.$refs.autofocus[0] !== "undefined") {
this.$refs.autofocus[0].focus();
}
} else {
this.$refs.autofocus.focus();
}
}
});
},
objectsEqual(obj1, obj2) {
return _.isEqual(obj1, obj2);
......@@ -347,8 +335,5 @@ export default {
return this.getIndexForQuestion(this.activeTab);
},
},
mounted() {
this.$refs.autofocus.focus();
},
}
</script>
......@@ -2,7 +2,7 @@
<div class="vote_edit">
<label>
{{ $gettext('Link eines Videos oder einer anderen Informationsseite (optional)') }}
<input type="url" v-model="val_clone.url" ref="infoUrl"
<input type="url" v-model="val_clone.url" v-autofocus ref="infoUrl"
@input="checkValidity()">
</label>
......@@ -26,7 +26,6 @@ export default {
});
},
mounted() {
this.$refs.infoUrl.focus();
this.checkValidity();
},
methods: {
......
<template>
<div class="rangescale_edit">
<div class="formpart" tabindex="0" ref="autofocus">
<div class="formpart" tabindex="0">
{{ $gettext('Einleitungstext') }}
<StudipWysiwyg v-model="val_clone.description" />
</div>
......@@ -68,9 +68,6 @@ export default {
statements: ['', '', '', '']
});
},
mounted() {
this.$refs.autofocus.focus();
},
computed: {
options() {
let result = [];
......
<template>
<div class="vote_edit">
<div class="formpart" tabindex="0" ref="autofocus">
<div class="formpart" tabindex="0">
{{ $gettext('Frage') }}
<StudipWysiwyg v-model="val_clone.description" />
</div>
......@@ -39,9 +39,6 @@ export default {
options: ['', '', '', ''],
randomize: '0',
});
},
mounted() {
this.$refs.autofocus.focus();
}
}
</script>
// Shamelessly copied from https://github.com/byteboomers/vue-autofocus-directive
function focusElement(el: HTMLElement, binding: any) : void {
if (binding.value && !binding.value) {
return;
}
el.focus()
}
export default {
bind(el: HTMLElement, binding: any, vnode: any) {
if (vnode.componentInstance?.focus instanceof Function) {
// When the component itself has a focus method
vnode.componentInstance.focus();
} else {
// When the component of the element gets activated
vnode.context.$on('hook:activated', () => focusElement(el, binding));
}
},
inserted: focusElement
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment