diff --git a/app/controllers/contents/courseware.php b/app/controllers/contents/courseware.php index 1551fbd72edd889cf9084e0977e4e6779065036b..f0d502320f67e01ddc1a631729e877997c73c201 100644 --- a/app/controllers/contents/courseware.php +++ b/app/controllers/contents/courseware.php @@ -48,7 +48,6 @@ class Contents_CoursewareController extends CoursewareController $sidebar = Sidebar::Get(); $sidebar->addWidget(new VueWidget('courseware-action-widget')); SkipLinks::addIndex(_('Aktionen'), 'courseware-action-widget', 21); - $sidebar->addWidget(new VueWidget('courseware-import-widget')); } /** diff --git a/app/controllers/course/courseware.php b/app/controllers/course/courseware.php index 401ab170f6b8f47ae7433e7e9930e90a232e6a69..f8e721e0b2eeec6d68fd160e79465c68fb98b5e5 100644 --- a/app/controllers/course/courseware.php +++ b/app/controllers/course/courseware.php @@ -285,7 +285,6 @@ class Course_CoursewareController extends CoursewareController $sidebar = Sidebar::Get(); $sidebar->addWidget(new VueWidget('courseware-action-widget')); SkipLinks::addIndex(_('Aktionen'), 'courseware-action-widget', 21); - $sidebar->addWidget(new VueWidget('courseware-import-widget')); } private function setTasksSidebar(): void diff --git a/app/controllers/courseware_controller.php b/app/controllers/courseware_controller.php index 91fc9c856bd9fcf158325bec3dc3afaf858b8ad9..eaec6093df4d53567a068e4d373a9b4cbce976ff 100644 --- a/app/controllers/courseware_controller.php +++ b/app/controllers/courseware_controller.php @@ -82,6 +82,5 @@ abstract class CoursewareController extends AuthenticatedController SkipLinks::addIndex(_('Aktionen'), 'courseware-action-widget', 21); $sidebar->addWidget(new VueWidget('courseware-search-widget')); $sidebar->addWidget(new VueWidget('courseware-view-widget')); - $sidebar->addWidget(new VueWidget('courseware-import-widget')); } } diff --git a/lib/classes/JsonApi/Routes/Courseware/UnitsCreate.php b/lib/classes/JsonApi/Routes/Courseware/UnitsCreate.php index f55fd6aa5468b653251a17ef638c88ca7839280f..a6159e3f41618a21733460c18a719d57a1ef8fcb 100644 --- a/lib/classes/JsonApi/Routes/Courseware/UnitsCreate.php +++ b/lib/classes/JsonApi/Routes/Courseware/UnitsCreate.php @@ -117,6 +117,10 @@ class UnitsCreate extends JsonApiController $instance->getUnit()->store(); + if (self::arrayGet($json, 'data.template.type') === 'topics') { + $struct->createChildrenFromCourseTopics(); + } + return $unit; } diff --git a/lib/models/Courseware/StructuralElement.php b/lib/models/Courseware/StructuralElement.php index bb325db4a90cf8094f48f169843f2976fe637abf..34cef8067af6228c07b47504b18d02b50902e1a8 100644 --- a/lib/models/Courseware/StructuralElement.php +++ b/lib/models/Courseware/StructuralElement.php @@ -1168,4 +1168,26 @@ SQL; } } + + public function createChildrenFromCourseTopics() + { + if ($this->range_type === 'user') { + return null; + } + $topics = \CourseTopic::findBySeminar_id($this->course->id); + foreach($topics as $key => $topic) { + self::create([ + 'parent_id' => $this->id, + 'range_id' => $this->range_id, + 'range_type' => $this->range_type, + 'owner_id' => $this->owner_id, + 'editor_id' => $this->editor_id, + 'edit_blocker_id' => '', + 'title' => $topic->title, + 'purpose' => $this->purpose, + 'payload' => '', + 'position' => $key + ]); + } + } } diff --git a/resources/vue/components/StudipSquareButton.vue b/resources/vue/components/StudipSquareButton.vue index b7ae400aa5f7eb7d55fc59902b7b189f09e199ad..04d7813921d38610a5e983c5e8db33dbe5aa7217 100644 --- a/resources/vue/components/StudipSquareButton.vue +++ b/resources/vue/components/StudipSquareButton.vue @@ -46,6 +46,7 @@ $size: 130px; } span { color: var(--base-color); + min-width: 110px; } &:hover span { color: var(--red); diff --git a/resources/vue/components/courseware/IndexApp.vue b/resources/vue/components/courseware/IndexApp.vue index 8b6f59d2396954c978c36a8072596bb2b73250a5..2ac86c2278d6e44bca3f1b04dea55a55da8ef23d 100644 --- a/resources/vue/components/courseware/IndexApp.vue +++ b/resources/vue/components/courseware/IndexApp.vue @@ -18,9 +18,6 @@ <MountingPortal mountTo="#courseware-view-widget" name="sidebar-views"> <courseware-view-widget v-if="!showSearchResults" :structural-element="selected" :canVisit="canVisit"></courseware-view-widget> </MountingPortal> - <MountingPortal mountTo="#courseware-import-widget" name="sidebar-import"> - <courseware-import-widget v-if="!showSearchResults && canEditSelected" :structural-element="selected"></courseware-import-widget> - </MountingPortal> </div> <studip-progress-indicator v-if="structureLoadingState === 'loading'" @@ -43,7 +40,6 @@ import CoursewareCompanionBox from './layouts/CoursewareCompanionBox.vue'; import CoursewareCompanionOverlay from './layouts/CoursewareCompanionOverlay.vue'; import CoursewareViewWidget from './widgets/CoursewareViewWidget.vue'; import CoursewareActionWidget from './widgets/CoursewareActionWidget.vue'; -import CoursewareImportWidget from './widgets/CoursewareImportWidget.vue'; import CoursewareSearchWidget from './widgets/CoursewareSearchWidget.vue'; import StudipProgressIndicator from '../StudipProgressIndicator.vue'; @@ -58,7 +54,6 @@ export default { CoursewareActionWidget, CoursewareCompanionBox, StudipProgressIndicator, - CoursewareImportWidget, CoursewareSearchWidget, CoursewareCompanionOverlay, }, diff --git a/resources/vue/components/courseware/ShelfApp.vue b/resources/vue/components/courseware/ShelfApp.vue index 7f0f274b04804491fc3e439b01b2c38e6ad9617e..d5877550ec44cdd4c929efa1507e8f63b417ac17 100644 --- a/resources/vue/components/courseware/ShelfApp.vue +++ b/resources/vue/components/courseware/ShelfApp.vue @@ -4,25 +4,25 @@ <courseware-unit-items /> <courseware-shared-items v-if="!inCourseContext" /> </div> - <courseware-shelf-dialog-add v-if="showUnitAddDialog" /> + <courseware-shelf-dialog-add-chooser v-if="showUnitAddDialog"/> + <courseware-shelf-dialog-add v-if="showUnitNewDialog" /> <courseware-shelf-dialog-copy v-if="showUnitCopyDialog" /> <courseware-shelf-dialog-import v-if="showUnitImportDialog" /> + <courseware-shelf-dialog-topics v-if="showUnitTopicsDialog" /> <MountingPortal v-if="userIsTeacher || !inCourseContext" mountTo="#courseware-action-widget" name="sidebar-actions"> <courseware-shelf-action-widget></courseware-shelf-action-widget> </MountingPortal> - <MountingPortal v-if="userIsTeacher || !inCourseContext" mountTo="#courseware-import-widget" name="sidebar-imports"> - <courseware-shelf-import-widget></courseware-shelf-import-widget> - </MountingPortal> <courseware-companion-overlay /> </div> </template> <script> import CoursewareShelfActionWidget from './widgets/CoursewareShelfActionWidget.vue'; -import CoursewareShelfImportWidget from './widgets/CoursewareShelfImportWidget.vue'; import CoursewareShelfDialogAdd from './unit/CoursewareShelfDialogAdd.vue'; +import CoursewareShelfDialogAddChooser from './unit/CoursewareShelfDialogAddChooser.vue'; import CoursewareShelfDialogCopy from './unit/CoursewareShelfDialogCopy.vue'; import CoursewareShelfDialogImport from './unit/CoursewareShelfDialogImport.vue'; +import CoursewareShelfDialogTopics from './unit/CoursewareShelfDialogTopics.vue'; import CoursewareUnitItems from './unit/CoursewareUnitItems.vue'; import CoursewareSharedItems from './unit/CoursewareSharedItems.vue'; import CoursewareCompanionOverlay from './layouts/CoursewareCompanionOverlay.vue'; @@ -32,10 +32,11 @@ import { mapActions, mapGetters } from 'vuex'; export default { components: { CoursewareShelfActionWidget, - CoursewareShelfImportWidget, CoursewareShelfDialogAdd, + CoursewareShelfDialogAddChooser, CoursewareShelfDialogCopy, CoursewareShelfDialogImport, + CoursewareShelfDialogTopics, CoursewareUnitItems, CoursewareSharedItems, CoursewareCompanionOverlay, @@ -46,6 +47,8 @@ export default { showUnitCopyDialog: 'showUnitCopyDialog', showUnitImportDialog: 'showUnitImportDialog', showUnitLinkDialog: 'showUnitLinkDialog', + showUnitNewDialog: 'showUnitNewDialog', + showUnitTopicsDialog: 'showUnitTopicsDialog', licenses: 'licenses', context:'context', userIsTeacher: 'userIsTeacher', @@ -56,13 +59,5 @@ export default { } }, - methods: { - ...mapActions({ - setShowUnitAddDialog: 'setShowUnitAddDialog', - setShowUnitCopyDialog: 'setShowUnitCopyDialog', - setShowUnitImportDialog: 'setShowUnitImportDialog', - setShowUnitLinkDialog: 'setShowUnitLinkDialog', - }), - }, } </script> diff --git a/resources/vue/components/courseware/structural-element/CoursewareStructuralElement.vue b/resources/vue/components/courseware/structural-element/CoursewareStructuralElement.vue index 03b2cec8c145c51e5e7dec2a3bab102afa79e377..9c93d172cbf7bb68e22d318860df889559219201 100644 --- a/resources/vue/components/courseware/structural-element/CoursewareStructuralElement.vue +++ b/resources/vue/components/courseware/structural-element/CoursewareStructuralElement.vue @@ -569,6 +569,7 @@ <courseware-structural-element-dialog-export-chooser v-if="showExportChooserDialog" :canEdit="canEdit" :canVisit="canVisit" /> <courseware-structural-element-dialog-export v-if="showExportDialog" :structuralElement="currentElement" /> <courseware-structural-element-dialog-export-pdf v-if="showPdfExportDialog" :structuralElement="currentElement" /> + <courseware-structural-element-dialog-add-chooser v-if="showAddChooserDialog" /> </div> <div v-else> <courseware-companion-box @@ -593,6 +594,7 @@ import CoursewarePluginComponents from '../plugin-components.js'; import CoursewareRootContent from './CoursewareRootContent.vue'; import CoursewareStructuralElementDialogAdd from './CoursewareStructuralElementDialogAdd.vue'; +import CoursewareStructuralElementDialogAddChooser from './CoursewareStructuralElementDialogAddChooser.vue'; import CoursewareStructuralElementDialogCopy from './CoursewareStructuralElementDialogCopy.vue'; import CoursewareStructuralElementDialogImport from './CoursewareStructuralElementDialogImport.vue'; import CoursewareStructuralElementDialogLink from './CoursewareStructuralElementDialogLink.vue'; @@ -618,6 +620,7 @@ export default { components: Object.assign(StructuralElementComponents, { CoursewareRootContent, CoursewareStructuralElementDialogAdd, + CoursewareStructuralElementDialogAddChooser, CoursewareStructuralElementDialogCopy, CoursewareStructuralElementDialogImport, CoursewareStructuralElementDialogLink, @@ -713,6 +716,7 @@ export default { pluginManager: 'pluginManager', showEditDialog: 'showStructuralElementEditDialog', showAddDialog: 'showStructuralElementAddDialog', + showAddChooserDialog: 'showStructuralElementAddChooserDialog', showImportDialog: 'showStructuralElementImportDialog', showCopyDialog: 'showStructuralElementCopyDialog', showLinkDialog: 'showStructuralElementLinkDialog', @@ -1225,6 +1229,7 @@ export default { setStockImageForStructuralElement: 'setStockImageForStructuralElement', showElementEditDialog: 'showElementEditDialog', showElementAddDialog: 'showElementAddDialog', + showElementAddChooserDialog: 'showElementAddChooserDialog', showElementExportDialog: 'showElementExportDialog', showElementPdfExportDialog: 'showElementPdfExportDialog', showElementInfoDialog: 'showElementInfoDialog', @@ -1276,7 +1281,7 @@ export default { break; case 'addElement': this.errorEmptyChapterName = false; - this.showElementAddDialog(true); + this.showElementAddChooserDialog(true); break; case 'deleteCurrentElement': await this.loadStructuralElement(this.currentId); diff --git a/resources/vue/components/courseware/structural-element/CoursewareStructuralElementDialogAddChooser.vue b/resources/vue/components/courseware/structural-element/CoursewareStructuralElementDialogAddChooser.vue new file mode 100644 index 0000000000000000000000000000000000000000..14d76379d3ddf991c25a0b6bf0a4815c118692e5 --- /dev/null +++ b/resources/vue/components/courseware/structural-element/CoursewareStructuralElementDialogAddChooser.vue @@ -0,0 +1,92 @@ +<template> + <studip-dialog + :title="$gettext('Seite hinzufügen')" + :closeText="$gettext('Schließen')" + closeClass="cancel" + height="320" + width="680" + @close="showElementAddChooserDialog(false)" + > + <template v-slot:dialogContent> + <div class="square-button-panel"> + <studip-square-button + icon="add" + :title="$gettext('Neu erstellen')" + @click="selectType('new')" + /> + <studip-square-button + icon="copy" + :title="$gettext('Bestehendes kopieren')" + @click="selectType('copy')" + /> + <studip-square-button + v-if="inCourseContext && userIsTeacher" + icon="copy" + :title="$gettext('Aus Arbeitsplatz verknüpfen')" + @click="selectType('link')" + /> + <studip-square-button + icon="import" + :title="$gettext('Aus Datei importieren')" + @click="selectType('import')" + /> + + </div> + </template> + </studip-dialog> +</template> + +<script> +import StudipSquareButton from './../../StudipSquareButton.vue'; +import { mapActions, mapGetters } from 'vuex'; + +export default { + name: 'courseware-shelf-dialog-add-chooser', + components: { + StudipSquareButton, + }, + computed: { + ...mapGetters({ + context: 'context', + userIsTeacher: 'userIsTeacher', + }), + inCourseContext() { + return this.context.type === 'courses'; + }, + }, + methods: { + ...mapActions({ + showElementAddDialog: 'showElementAddDialog', + showElementAddChooserDialog: 'showElementAddChooserDialog', + showElementImportDialog: 'showElementImportDialog', + showElementCopyDialog: 'showElementCopyDialog', + showElementLinkDialog: 'showElementLinkDialog', + }), + selectType(type) { + switch (type) { + case 'new': + this.showElementAddDialog(true); + break; + case 'import': + this.showElementImportDialog(true); + break; + case 'copy': + this.showElementCopyDialog(true); + break; + case 'link': + this.showElementLinkDialog(true) + } + this.showElementAddChooserDialog(false); + }, + }, +}; +</script> +<style scoped lang="scss"> +.square-button-panel { + display: flex; + flex-direction: row; + flex-wrap: wrap; + width: 100%; + justify-content: center; +} +</style> diff --git a/resources/vue/components/courseware/unit/CoursewareShelfDialogAdd.vue b/resources/vue/components/courseware/unit/CoursewareShelfDialogAdd.vue index ea738a6553f2564c2a0fc3ead742c3698dc0400b..43163ecf8d85fc73f52ff8df76d5a917ea5d205e 100644 --- a/resources/vue/components/courseware/unit/CoursewareShelfDialogAdd.vue +++ b/resources/vue/components/courseware/unit/CoursewareShelfDialogAdd.vue @@ -6,7 +6,7 @@ :slots="wizardSlots" :lastRequiredSlotId="1" :requirements="requirements" - @close="setShowUnitAddDialog(false)" + @close="setShowUnitNewDialog(false)" @confirm="createUnit" > <template v-slot:basic> @@ -208,7 +208,7 @@ export default { companionInfo: 'companionInfo', companionSuccess: 'companionSuccess', createCoursewareUnit: 'courseware-units/create', - setShowUnitAddDialog: 'setShowUnitAddDialog', + setShowUnitNewDialog: 'setShowUnitNewDialog', setStockImageForStructuralElement: 'setStockImageForStructuralElement', loadStructuralElementById: 'courseware-structural-elements/loadById', uploadImageForStructuralElement: 'uploadImageForStructuralElement', @@ -276,7 +276,7 @@ export default { } } }; - this.setShowUnitAddDialog(false); + this.setShowUnitNewDialog(false); await this.createCoursewareUnit(unit, { root: true }); this.companionSuccess({ info: this.$gettext('Neues Lernmaterial angelegt.') }); diff --git a/resources/vue/components/courseware/unit/CoursewareShelfDialogAddChooser.vue b/resources/vue/components/courseware/unit/CoursewareShelfDialogAddChooser.vue new file mode 100644 index 0000000000000000000000000000000000000000..8e03ffd4213d38836b8ae20e6804da87d95617bf --- /dev/null +++ b/resources/vue/components/courseware/unit/CoursewareShelfDialogAddChooser.vue @@ -0,0 +1,91 @@ +<template> + <studip-dialog + :title="$gettext('Lernmaterial hinzufügen')" + :closeText="$gettext('Schließen')" + closeClass="cancel" + height="320" + width="680" + @close="setShowUnitAddDialog(false)" + > + <template v-slot:dialogContent> + <div class="square-button-panel"> + <studip-square-button + icon="add" + :title="$gettext('Neu erstellen')" + @click="selectType('new')" + /> + <studip-square-button + v-if="inCourseContext" + icon="schedule" + :title="$gettext('Neu, Struktur aus Ablaufplan')" + @click="selectType('topics')" + /> + <studip-square-button + icon="copy" + :title="$gettext('Bestehendes kopieren')" + @click="selectType('copy')" + /> + <studip-square-button + icon="import" + :title="$gettext('Aus Datei importieren')" + @click="selectType('import')" + /> + </div> + </template> + </studip-dialog> +</template> + +<script> +import StudipSquareButton from './../../StudipSquareButton.vue'; +import { mapActions, mapGetters } from 'vuex'; + +export default { + name: 'courseware-shelf-dialog-add-chooser', + components: { + StudipSquareButton, + }, + computed: { + ...mapGetters({ + context: 'context', + }), + inCourseContext() { + return this.context.type === 'courses'; + }, + }, + methods: { + ...mapActions({ + setShowUnitAddDialog: 'setShowUnitAddDialog', + setShowUnitCopyDialog: 'setShowUnitCopyDialog', + setShowUnitImportDialog: 'setShowUnitImportDialog', + setShowUnitLinkDialog: 'setShowUnitLinkDialog', + setShowUnitNewDialog: 'setShowUnitNewDialog', + setShowUnitTopicsDialog: 'setShowUnitTopicsDialog', + }), + selectType(type) { + switch (type) { + case 'new': + this.setShowUnitNewDialog(true); + break; + case 'import': + this.setShowUnitImportDialog(true); + break; + case 'copy': + this.setShowUnitCopyDialog(true); + break; + case 'topics': + this.setShowUnitTopicsDialog(true); + } + this.setShowUnitAddDialog(false); + }, + }, +}; +</script> +<style scoped lang="scss"> +.square-button-panel { + display: flex; + flex-direction: row; + flex-wrap: wrap; + width: 100%; + justify-content: center; +} +</style> diff --git a/resources/vue/components/courseware/unit/CoursewareShelfDialogTopics.vue b/resources/vue/components/courseware/unit/CoursewareShelfDialogTopics.vue new file mode 100644 index 0000000000000000000000000000000000000000..eb6e88895fc34837251dd8d0a64c008baef1f09d --- /dev/null +++ b/resources/vue/components/courseware/unit/CoursewareShelfDialogTopics.vue @@ -0,0 +1,232 @@ +<template> + <studip-dialog + :title="$gettext('Lernmaterial aus Ablaufplan Themen erstellen')" + :confirmText="$gettext('Erstellen')" + confirmClass="accept" + :closeText="$gettext('Abbrechen')" + closeClass="cancel" + height="450" + width="500" + @close="setShowUnitTopicsDialog(false)" + @confirm="createUnit" + > + <template v-slot:dialogContent> + <form class="default" @submit.prevent=""> + <courseware-collapsible-box :title="$gettext('Grundeinstellungen')" :open="true" > + <label class="studiprequired"> + {{ text.title }} + <span :title="$gettext('Dies ist ein Pflichtfeld')" aria-hidden="true" class="asterisk">*</span> + <input type="text" v-model="title" required /> + </label> + <label class="studiprequired"> + {{ text.description }} + <span :title="$gettext('Dies ist ein Pflichtfeld')" aria-hidden="true" class="asterisk">*</span> + <textarea v-model="description" required /> + </label> + </courseware-collapsible-box> + <courseware-collapsible-box :title="$gettext('Darstellung')" > + <label> + {{ $gettext('Bild hochladen') }} + <br> + <input + class="cw-file-input" + ref="upload_image" + type="file" + accept="image/*" + @change="checkUploadFile" + > + <CoursewareCompanionBox + v-if="uploadFileError" + :msgCompanion="uploadFileError" + mood="sad" + class="cw-companion-box-in-form" + /> + </label> + <template v-if="selectedStockImage"> + <StockImageSelectableImageCard :stock-image="selectedStockImage" /> + <label> + <button class="button" type="button" @click="selectedStockImage = null"> + {{ $gettext('Bild entfernen') }} + </button> + </label> + </template> + <label v-else> + {{ $gettext('oder') }} + <br> + <button class="button" type="button" @click="showStockImageSelector = true"> + {{ $gettext('Aus dem Bilderpool auswählen') }} + </button> + <StockImageSelector + v-if="showStockImageSelector" + @close="showStockImageSelector = false" + @select="onSelectStockImage" + /> + </label> + <label> + {{ $gettext('Farbe') }} + <studip-select v-model="color" :options="colors" :reduce="(color) => color.class" label="class"> + <template #open-indicator="selectAttributes"> + <span v-bind="selectAttributes"><studip-icon shape="arr_1down" :size="10" /></span> + </template> + <template #no-options> + {{ $gettext('Es steht keine Auswahl zur Verfügung.') }} + </template> + <template #selected-option="{ name, hex }"> + <span class="vs__option-color" :style="{ 'background-color': hex }"></span> + <span>{{ name }}</span> + </template> + <template #option="{ name, hex }"> + <span class="vs__option-color" :style="{ 'background-color': hex }"></span + ><span>{{ name }}</span> + </template> + </studip-select> + </label> + </courseware-collapsible-box> + </form> + </template> + </studip-dialog> +</template> + +<script> +import CoursewareCollapsibleBox from '../layouts/CoursewareCollapsibleBox.vue'; +import StockImageSelectableImageCard from '../../stock-images/SelectableImageCard.vue'; +import StockImageSelector from '../../stock-images/SelectorDialog.vue'; +import StudipSelect from '../../StudipSelect.vue'; +import colorMixin from '@/vue/mixins/courseware/colors.js'; + +import { mapActions, mapGetters } from 'vuex'; + +export default { + name: 'courseware-shelf-dialog-topics', + mixins: [colorMixin], + components: { + CoursewareCollapsibleBox, + StockImageSelectableImageCard, + StockImageSelector, + StudipSelect, + }, + data() { + return { + title: '', + description: '', + color: 'studip-blue', + uploadFileError: '', + showStockImageSelector: false, + selectedStockImage: null, + + text: { + title: this.$gettext('Titel des Lernmaterials'), + description: this.$gettext('Beschreibung'), + }, + }; + }, + computed: { + ...mapGetters({ + context: 'context', + lastCreateCoursewareUnit: 'courseware-units/lastCreated', + structuralElementById: 'courseware-structural-elements/byId', + }), + colors() { + return this.mixinColors.filter((color) => color.darkmode); + }, + }, + methods: { + ...mapActions({ + companionError: 'companionError', + companionInfo: 'companionInfo', + companionSuccess: 'companionSuccess', + createCoursewareUnit: 'courseware-units/create', + setShowUnitTopicsDialog: 'setShowUnitTopicsDialog', + loadStructuralElementById: 'courseware-structural-elements/loadById', + uploadImageForStructuralElement: 'uploadImageForStructuralElement', + }), + checkUploadFile() { + const file = this.$refs?.upload_image?.files[0]; + if (file.size > 2097152) { + this.uploadFileError = this.$gettext( + 'Diese Datei ist zu groß. Bitte wählen Sie eine Datei aus, die kleiner als 2MB ist.' + ); + } else if (!file.type.includes('image')) { + this.uploadFileError = this.$gettext('Diese Datei ist kein Bild. Bitte wählen Sie ein Bild aus.'); + } else { + this.uploadFileError = ''; + this.selectedStockImage = null; + } + }, + async createUnit() { + if (this.title === '') { + this.companionError({ + info: this.$gettext('Bitte geben Sie einen Titel ein.'), + }); + return false; + } + if (this.description === '') { + this.companionError({ + info: this.$gettext('Bitte geben Sie eine Beschreibung ein.'), + }); + return false; + } + const file = this.$refs?.upload_image?.files[0]; + const unit = { + attributes: { + title: this.title, + purpose: 'content', + payload: { + description: this.description, + color: this.color, + license_type: '', + required_time: '', + difficulty_start: '', + difficulty_end: '', + }, + }, + relationships: { + range: { + data: { + type: this.context.type, + id: this.context.id, + }, + }, + }, + template: { + type: 'topics', + }, + }; + await this.createCoursewareUnit(unit, { root: true }); + this.setShowUnitTopicsDialog(false); + + const newElementId = this.lastCreateCoursewareUnit.relationships['structural-element'].data.id; + await this.loadStructuralElementById({ id: newElementId }); + let newStructuralElement = this.structuralElementById({ id: newElementId }); + + try { + if (file) { + await this.uploadImageForStructuralElement({ + structuralElement: newStructuralElement, + file, + }); + } else if (this.selectedStockImage) { + await this.setStockImageForStructuralElement({ + structuralElement: newStructuralElement, + stockImage: this.selectedStockImage, + }); + } + + this.loadStructuralElementById({ id: newStructuralElement.id, options: { include: 'children' } }); + } catch (error) { + console.error(error); + this.companionError({ + info: this.$gettext('Das Bild für das neue Lernmaterial konnte nicht gespeichert werden.'), + }); + } + }, + onSelectStockImage(stockImage) { + if (this.$refs?.upload_image) { + this.$refs.upload_image.value = null; + } + this.selectedStockImage = stockImage; + this.showStockImageSelector = false; + }, + }, +}; +</script> diff --git a/resources/vue/components/courseware/unit/CoursewareUnitItems.vue b/resources/vue/components/courseware/unit/CoursewareUnitItems.vue index f0973de68696b748affb57f5f0783f9558c8e573..e805e1104bc76b88ff3738ff4b304ff8e3285213 100644 --- a/resources/vue/components/courseware/unit/CoursewareUnitItems.vue +++ b/resources/vue/components/courseware/unit/CoursewareUnitItems.vue @@ -49,7 +49,7 @@ ) }} </p> - <button class="button" @click="setShowUnitAddDialog(true)"> + <button class="button" @click="setShowUnitNewDialog(true)"> {{ $gettext('Neues Lernmaterial anlegen') }} </button> </div> @@ -63,16 +63,10 @@ <div v-if="!hasUnits && !inCourseContext" class="cw-contents-overview-teaser"> <div class="cw-contents-overview-teaser-content"> <header>{{ $gettext('Ihre persönlichen Lernmaterialien') }}</header> - <p> - {{ - $gettext( - 'Erstellen und verwalten Sie hier Ihre eigenen persönlichen Lernmaterialien in Form von ePorfolios, ' + - 'Vorlagen für Veranstaltungen oder einfach nur persönliche Inhalte für das Studium. ' + - 'Entwickeln Sie Ihre eigenen (Lehr-)Materialien für Studium oder die Lehre und teilen diese mit anderen Nutzenden.' - ) - }} - </p> - <button class="button" @click="setShowUnitAddDialog(true)"> + <p>{{ $gettext('Erstellen und verwalten Sie hier Ihre eigenen persönlichen Lernmaterialien in Form von ePorfolios, ' + + 'Vorlagen für Veranstaltungen oder einfach nur persönliche Inhalte für das Studium. ' + + 'Entwickeln Sie Ihre eigenen (Lehr-)Materialien für Studium oder die Lehre und teilen diese mit anderen Nutzenden.') }}</p> + <button class="button" @click="setShowUnitNewDialog(true)"> {{ $gettext('Neues Lernmaterial anlegen') }} </button> </div> @@ -131,6 +125,7 @@ export default { methods: { ...mapActions({ setShowUnitAddDialog: 'setShowUnitAddDialog', + setShowUnitNewDialog: 'setShowUnitNewDialog', sortUnits: 'sortUnits', }), initCurrentData() { diff --git a/resources/vue/components/courseware/widgets/CoursewareActionWidget.vue b/resources/vue/components/courseware/widgets/CoursewareActionWidget.vue index 800d47f7775aff8727c5fcace5a5d5af6d071453..9a179c3aec33aab9c64296f4a5c2c9fa63849994 100644 --- a/resources/vue/components/courseware/widgets/CoursewareActionWidget.vue +++ b/resources/vue/components/courseware/widgets/CoursewareActionWidget.vue @@ -39,9 +39,10 @@ export default { ...mapActions({ showElementAddDialog: 'showElementAddDialog', showElementExportChooserDialog: 'showElementExportChooserDialog', + showElementAddChooserDialog: 'showElementAddChooserDialog', }), addElement() { - this.showElementAddDialog(true); + this.showElementAddChooserDialog(true); }, exportElement() { this.showElementExportChooserDialog(true); diff --git a/resources/vue/store/courseware/courseware-shelf.module.js b/resources/vue/store/courseware/courseware-shelf.module.js index 52cef5f7960ba8ee92f989eb3c8abd9131b2cc5a..641ec51af4c881d86d1ea4cd97dbe22c730040c3 100644 --- a/resources/vue/store/courseware/courseware-shelf.module.js +++ b/resources/vue/store/courseware/courseware-shelf.module.js @@ -10,6 +10,8 @@ const getDefaultState = () => { showUnitCopyDialog: false, showUnitImportDialog: false, showUnitLinkDialog: false, + showUnitNewDialog: false, + showUnitTopicsDialog: false, licenses: null, userId: null, exportState: '', @@ -59,6 +61,12 @@ const getters = { showUnitLinkDialog(state) { return state.showUnitLinkDialog; }, + showUnitNewDialog(state) { + return state.showUnitNewDialog; + }, + showUnitTopicsDialog(state) { + return state.showUnitTopicsDialog; + }, licenses(state) { return state.licenses; }, @@ -119,6 +127,12 @@ export const actions = { setShowUnitLinkDialog({ commit }, show) { commit('setShowUnitLinkDialog', show); }, + setShowUnitNewDialog({ commit }, show) { + commit('setShowUnitNewDialog', show); + }, + setShowUnitTopicsDialog({ commit }, show) { + commit('setShowUnitTopicsDialog', show); + }, setLicenses({ commit }, licenses) { commit('setLicenses', licenses); }, @@ -743,6 +757,12 @@ export const mutations = { setShowUnitLinkDialog(state, data) { state.showUnitLinkDialog = data; }, + setShowUnitNewDialog(state, data) { + state.showUnitNewDialog = data; + }, + setShowUnitTopicsDialog(state, data) { + state.showUnitTopicsDialog = data; + }, setLicenses(state, data) { state.licenses = data; }, diff --git a/resources/vue/store/courseware/courseware.module.js b/resources/vue/store/courseware/courseware.module.js index 1c969bec2644b36b31656a47c9b8c18d1f751b8c..1f85d56b0e766c720470af01210e939081f629a7 100644 --- a/resources/vue/store/courseware/courseware.module.js +++ b/resources/vue/store/courseware/courseware.module.js @@ -27,6 +27,7 @@ const getDefaultState = () => { showStructuralElementEditDialog: false, showStructuralElementAddDialog: false, + showStructuralElementAddChooserDialog: false, showStructuralElementImportDialog: false, showStructuralElementCopyDialog: false, showStructuralElementLinkDialog: false, @@ -181,6 +182,9 @@ const getters = { showStructuralElementAddDialog(state) { return state.showStructuralElementAddDialog; }, + showStructuralElementAddChooserDialog(state) { + return state.showStructuralElementAddChooserDialog; + }, showStructuralElementCopyDialog(state) { return state.showStructuralElementCopyDialog; }, @@ -901,6 +905,10 @@ export const actions = { context.commit('setShowStructuralElementAddDialog', bool); }, + showElementAddChooserDialog(context, bool) { + context.commit('setShowStructuralElementAddChooserDialog', bool); + }, + showElementImportDialog(context, bool) { context.commit('setShowStructuralElementImportDialog', bool); }, @@ -1523,6 +1531,10 @@ export const mutations = { state.showStructuralElementAddDialog = showAdd; }, + setShowStructuralElementAddChooserDialog(state, showAddChooser) { + state.showStructuralElementAddChooserDialog = showAddChooser; + }, + setShowStructuralElementImportDialog(state, showImport) { state.showStructuralElementImportDialog = showImport; },