aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.json10
-rw-r--r--package.json2
-rw-r--r--resources/assets/javascripts/bootstrap/oer.js18
-rw-r--r--resources/assets/javascripts/lib/blubber.js38
-rw-r--r--resources/assets/javascripts/lib/files.js24
-rw-r--r--resources/assets/javascripts/lib/oer.js22
-rw-r--r--resources/vue/components/BlubberGlobalstream.vue19
-rw-r--r--resources/vue/components/BlubberThread.vue101
-rw-r--r--resources/vue/components/BlubberThreadWidget.vue9
-rw-r--r--resources/vue/components/CacheAdministration.vue8
-rw-r--r--resources/vue/components/Datetimepicker.vue2
-rw-r--r--resources/vue/components/EditableList.vue38
-rw-r--r--resources/vue/components/FilesTable.vue49
-rw-r--r--resources/vue/components/I18nTextarea.vue37
-rw-r--r--resources/vue/components/MyCoursesColorPicker.vue2
-rw-r--r--resources/vue/components/MyCoursesNavigation.vue2
-rw-r--r--resources/vue/components/MyCoursesTables.vue2
-rw-r--r--resources/vue/components/MyCoursesTiles.vue8
-rw-r--r--resources/vue/components/StudipDialog.vue3
-rw-r--r--resources/vue/components/StudipFileSize.vue2
-rw-r--r--resources/vue/components/StudipMessageBox.vue6
-rw-r--r--resources/vue/components/courseware/CoursewareAccordionContainer.vue4
-rw-r--r--resources/vue/components/courseware/CoursewareActionWidget.vue2
-rwxr-xr-xresources/vue/components/courseware/CoursewareBiographyAchievementsBlock.vue2
-rwxr-xr-xresources/vue/components/courseware/CoursewareBiographyGoalsBlock.vue2
-rwxr-xr-xresources/vue/components/courseware/CoursewareBiographyPersonalInformationBlock.vue2
-rw-r--r--resources/vue/components/courseware/CoursewareChartBlock.vue2
-rw-r--r--resources/vue/components/courseware/CoursewareContentBookmarks.vue1
-rw-r--r--resources/vue/components/courseware/CoursewareContentOverviewElements.vue4
-rwxr-xr-xresources/vue/components/courseware/CoursewareContentPermissions.vue1
-rw-r--r--resources/vue/components/courseware/CoursewareDefaultBlock.vue8
-rw-r--r--resources/vue/components/courseware/CoursewareDefaultContainer.vue1
-rw-r--r--resources/vue/components/courseware/CoursewareDialogCardsBlock.vue6
-rw-r--r--resources/vue/components/courseware/CoursewareHeadlineBlock.vue8
-rw-r--r--resources/vue/components/courseware/CoursewareImageMapBlock.vue14
-rw-r--r--resources/vue/components/courseware/CoursewareKeyPointBlock.vue5
-rw-r--r--resources/vue/components/courseware/CoursewareManagerCopySelector.vue6
-rw-r--r--resources/vue/components/courseware/CoursewareManagerElement.vue5
-rw-r--r--resources/vue/components/courseware/CoursewareManagerLinkSelector.vue8
-rw-r--r--resources/vue/components/courseware/CoursewareStructuralElement.vue16
-rw-r--r--resources/vue/components/courseware/CoursewareTabs.vue8
-rw-r--r--resources/vue/components/courseware/CoursewareTabsContainer.vue4
-rwxr-xr-xresources/vue/components/courseware/CoursewareTimelineBlock.vue6
-rw-r--r--resources/vue/components/courseware/CoursewareToolsAdmin.vue1
44 files changed, 269 insertions, 249 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index d9a963e..55c17a0 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -1,13 +1,16 @@
{
- "parser": "@babel/eslint-parser",
"parserOptions": {
+ "parser": "@babel/eslint-parser",
"sourceType": "module"
},
"env": {
"browser": true,
"es6": true
},
- "extends": "eslint:recommended",
+ "extends": [
+ "eslint:recommended",
+ "plugin:vue/essential"
+ ],
"globals": {
"STUDIP": "writable",
"CKEDITOR": "writable",
@@ -15,6 +18,9 @@
"_": "writable",
"jQuery": "writable"
},
+ "plugins": [
+ "vue"
+ ],
"rules": {
"no-unused-vars": "off",
diff --git a/package.json b/package.json
index 18f37b3..7d8898b 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
"description": "Stud.IP",
"private": true,
"scripts": {
- "lint": "eslint resources/assets/javascripts resources/vue",
+ "lint": "eslint --ext .js,.vue resources/assets/javascripts resources/vue",
"css-lint": "stylelint resources/assets/stylesheets",
"webpack-dev": "webpack --config webpack.dev.js --mode development",
"webpack-prod": "webpack --config webpack.prod.js --mode production",
diff --git a/resources/assets/javascripts/bootstrap/oer.js b/resources/assets/javascripts/bootstrap/oer.js
index eff927f..2b47149 100644
--- a/resources/assets/javascripts/bootstrap/oer.js
+++ b/resources/assets/javascripts/bootstrap/oer.js
@@ -57,14 +57,16 @@ STUDIP.ready(() => {
STUDIP.Vue.load().then(({createApp}) => {
STUDIP.OER.EditApp = createApp({
el: '.oercampus_editmaterial',
- data: {
- name: $('.oercampus_editmaterial input.oername').val(),
- logo_url: $('.oercampus_editmaterial .logo_file').data("oldurl"),
- customlogo: $('.oercampus_editmaterial .logo_file').data("customlogo"),
- filename: $('.oercampus_editmaterial .file.drag-and-drop').data("filename"),
- filesize: $('.oercampus_editmaterial .file.drag-and-drop').data("filesize"),
- tags: $('.oercampus_editmaterial .oer_tags').data("defaulttags"),
- minimumTags: 5
+ data() {
+ return {
+ name: $('.oercampus_editmaterial input.oername').val(),
+ logo_url: $('.oercampus_editmaterial .logo_file').data("oldurl"),
+ customlogo: $('.oercampus_editmaterial .logo_file').data("customlogo"),
+ filename: $('.oercampus_editmaterial .file.drag-and-drop').data("filename"),
+ filesize: $('.oercampus_editmaterial .file.drag-and-drop').data("filesize"),
+ tags: $('.oercampus_editmaterial .oer_tags').data("defaulttags"),
+ minimumTags: 5
+ };
},
mounted: function () {
jQuery("#difficulty_slider_edit").slider({
diff --git a/resources/assets/javascripts/lib/blubber.js b/resources/assets/javascripts/lib/blubber.js
index 6a72382..777f221 100644
--- a/resources/assets/javascripts/lib/blubber.js
+++ b/resources/assets/javascripts/lib/blubber.js
@@ -19,13 +19,15 @@ const Blubber = {
STUDIP.Vue.load().then(({createApp}) => {
STUDIP.Blubber.App = createApp({
el: '#layout_container',
- data: {
- threads: $('.blubber_threads_widget').data('threads_data'),
- thread_data: panel_data.thread_data,
- active_thread: panel_data.active_thread,
- threads_more_down: panel_data.threads_more_down,
- waiting: false,
- display_context_posting: 0
+ data() {
+ return {
+ threads: $('.blubber_threads_widget').data('threads_data'),
+ thread_data: panel_data.thread_data,
+ active_thread: panel_data.active_thread,
+ threads_more_down: panel_data.threads_more_down,
+ waiting: false,
+ display_context_posting: 0
+ };
},
methods: {
changeActiveThread: function (thread_id) {
@@ -96,13 +98,15 @@ const Blubber = {
STUDIP.Vue.load().then(({createApp}) => {
createApp({
el: this,
- data: {
- threads: panel_data.threads_data,
- thread_data: panel_data.thread_data,
- active_thread: panel_data.active_thread,
- threads_more_down: panel_data.threads_more_down,
- waiting: false,
- display_context_posting: 0
+ data () {
+ return {
+ threads: panel_data.threads_data,
+ thread_data: panel_data.thread_data,
+ active_thread: panel_data.active_thread,
+ threads_more_down: panel_data.threads_more_down,
+ waiting: false,
+ display_context_posting: 0
+ };
},
components,
});
@@ -186,8 +190,10 @@ const Blubber = {
let components = STUDIP.Blubber.components;
return createApp({
el: '#blubber_contact_ids',
- data: {
- users: []
+ data () {
+ return {
+ users: []
+ };
},
methods: {
addUser: function (user_id, name) {
diff --git a/resources/assets/javascripts/lib/files.js b/resources/assets/javascripts/lib/files.js
index 9d06a18..c013107 100644
--- a/resources/assets/javascripts/lib/files.js
+++ b/resources/assets/javascripts/lib/files.js
@@ -10,11 +10,13 @@ const Files = {
STUDIP.Vue.load().then(({createApp}) => {
this.filesapp = createApp({
el: "#layout_content",
- data: {
- "files": jQuery("#files_table_form").data("files") || [],
- "folders": jQuery("#files_table_form").data("folders") || [],
- "topfolder": jQuery("#files_table_form").data("topfolder"),
- "breadcrumbs": jQuery("#files_table_form").data("breadcrumbs") || []
+ data() {
+ return {
+ files: jQuery("#files_table_form").data("files") || [],
+ folders: jQuery("#files_table_form").data("folders") || [],
+ topfolder: jQuery("#files_table_form").data("topfolder"),
+ breadcrumbs: jQuery("#files_table_form").data("breadcrumbs") || []
+ };
},
methods: {
hasFilesOfType (type) {
@@ -45,11 +47,13 @@ const Files = {
STUDIP.Vue.load().then(({createApp}) => {
createApp({
el: table,
- data: {
- "files": jQuery(table).data("files") || [],
- "folders": jQuery(table).data("folders") || [],
- "topfolder": jQuery(table).data("topfolder"),
- "breadcrumbs": jQuery(table).data("breadcrumbs") || []
+ data() {
+ return {
+ files: jQuery(table).data("files") || [],
+ folders: jQuery(table).data("folders") || [],
+ topfolder: jQuery(table).data("topfolder"),
+ breadcrumbs: jQuery(table).data("breadcrumbs") || []
+ };
},
components: { FilesTable, },
});
diff --git a/resources/assets/javascripts/lib/oer.js b/resources/assets/javascripts/lib/oer.js
index dac19ec..0542a1e 100644
--- a/resources/assets/javascripts/lib/oer.js
+++ b/resources/assets/javascripts/lib/oer.js
@@ -37,16 +37,18 @@ const OER = {
STUDIP.Vue.load().then(({createApp}) => {
STUDIP.OER.Search = createApp({
el: ".oer_search",
- data: {
- browseMode: false,
- tags: $(".oer_search").data("tags"),
- tagHistory: [],
- searchtext: "",
- activeFilterPanel: false,
- difficulty: [1, 12],
- category: null,
- results: false,
- material_select_url_template: $(".oer_search").data("material_select_url_template")
+ data() {
+ return {
+ browseMode: false,
+ tags: $(".oer_search").data("tags"),
+ tagHistory: [],
+ searchtext: "",
+ activeFilterPanel: false,
+ difficulty: [1, 12],
+ category: null,
+ results: false,
+ material_select_url_template: $(".oer_search").data("material_select_url_template")
+ };
},
methods: {
sync_search_text: function () {
diff --git a/resources/vue/components/BlubberGlobalstream.vue b/resources/vue/components/BlubberGlobalstream.vue
index 0c4976c..548e1fd 100644
--- a/resources/vue/components/BlubberGlobalstream.vue
+++ b/resources/vue/components/BlubberGlobalstream.vue
@@ -3,7 +3,7 @@
<div class="scrollable_area" v-scroll>
<blubber-public-composer></blubber-public-composer>
<ol class="postings" aria-live="polite">
- <li class="more" v-if="stream_data.more_up">
+ <li class="more" v-if="streamData.more_up">
<studip-asset-img file="ajax-indicator-black.svg" width="20"></studip-asset-img>
</li>
@@ -37,7 +37,8 @@
name: 'blubber-globalstream',
data: function () {
return {
- already_loading_down: 0
+ already_loading_down: 0,
+ streamData: this.stream_data,
};
},
props: ['stream_data', 'more_down'],
@@ -52,14 +53,14 @@
addPosting: function (posting) {
let exists = false;
for (let i in this.stream_data) {
- if (this.stream_data[i].thread_id === posting.thread_id) {
+ if (this.streamData[i].thread_id === posting.thread_id) {
exists = true;
return;
}
}
if (!exists) {
posting.class = posting.class + " new";
- this.stream_data.push(posting);
+ this.streamData.push(posting);
this.$nextTick(() => {
STUDIP.Markup.element($(this.$el).find(`.postings > li[data-thread_id="${posting.thread_id}"]`));
});
@@ -74,8 +75,8 @@
});
},
computed: {
- sortedPostings: function () {
- return this.stream_data.sort((a, b) => b.mkdate - a.mkdate);
+ sortedPostings() {
+ return [...this.streamData].sort((a, b) => b.mkdate - a.mkdate);
}
},
directives: {
@@ -94,9 +95,9 @@
stream.already_loading_down = 1;
let earliest_mkdate = null;
- for (let i in stream.stream_data) {
- if ((earliest_mkdate === null) || stream.stream_data[i].mkdate < earliest_mkdate) {
- earliest_mkdate = stream.stream_data[i].mkdate;
+ for (let i in stream.streamData) {
+ if ((earliest_mkdate === null) || stream.streamData[i].mkdate < earliest_mkdate) {
+ earliest_mkdate = stream.streamData[i].mkdate;
}
}
//load older comments
diff --git a/resources/vue/components/BlubberThread.vue b/resources/vue/components/BlubberThread.vue
index bb742fe..a3a5d70 100644
--- a/resources/vue/components/BlubberThread.vue
+++ b/resources/vue/components/BlubberThread.vue
@@ -1,13 +1,13 @@
<template>
<div class="blubber_thread" :class="{dragover: dragging}"
- :id="'blubberthread_' + thread_data.thread_posting.thread_id"
+ :id="'blubberthread_' + threadData.thread_posting.thread_id"
@dragover.prevent="dragover" @dragleave.prevent="dragleave"
@drop.prevent="upload">
- <div class="responsive-visible context_info" v-if="thread_data.notifications">
+ <div class="responsive-visible context_info" v-if="threadData.notifications">
<a href="#"
@click.prevent="toggleFollow()"
class="followunfollow"
- :class="{unfollowed: !thread_data.followed}"
+ :class="{unfollowed: !threadData.followed}"
:title="$gettext('Benachrichtigungen für diese Konversation abstellen.')"
:data-thread_id="thread_data.thread_posting.thread_id">
<StudipIcon shape="decline" :size="20" class="follow text-bottom"></StudipIcon>
@@ -17,23 +17,23 @@
</div>
<div class="scrollable_area" v-scroll>
<div class="all_content">
- <div class="thread_posting" v-if="hasContent(thread_data.thread_posting.content)">
+ <div class="thread_posting" v-if="hasContent(threadData.thread_posting.content)">
<div class="contextinfo">
- <studip-date-time :timestamp="thread_data.thread_posting.mkdate" :relative="true"></studip-date-time>
- <a :href="getUserProfileURL(thread_data.thread_posting.user_id, thread_data.thread_posting.user_username)">{{ thread_data.thread_posting.user_name }}</a>
- <a :href="getUserProfileURL(thread_data.thread_posting.user_id, thread_data.thread_posting.user_username)" class="avatar" :style="{ backgroundImage: 'url(' + thread_data.thread_posting.avatar + ')' }"></a>
+ <studip-date-time :timestamp="threadData.thread_posting.mkdate" :relative="true"></studip-date-time>
+ <a :href="getUserProfileURL(threadData.thread_posting.user_id, threadData.thread_posting.user_username)">{{ threadData.thread_posting.user_name }}</a>
+ <a :href="getUserProfileURL(threadData.thread_posting.user_id, threadData.thread_posting.user_username)" class="avatar" :style="{ backgroundImage: 'url(' + threadData.thread_posting.avatar + ')' }"></a>
</div>
- <div class="content" v-html="thread_data.thread_posting.html"></div>
+ <div class="content" v-html="threadData.thread_posting.html"></div>
<div class="link_to_comments"></div>
</div>
- <div v-if="!hasContent(thread_data.thread_posting.content) && !thread_data.comments.length" class="empty_blubber_background">
+ <div v-if="!hasContent(threadData.thread_posting.content) && !threadData.comments.length" class="empty_blubber_background">
<div v-translate>Starte die Konversation jetzt!</div>
</div>
<ol class="comments" aria-live="polite">
- <li class="more" v-if="thread_data.more_up">
+ <li class="more" v-if="threadData.more_up">
<studip-asset-img file="ajax-indicator-black.svg" width="20"></studip-asset-img>
</li>
@@ -61,14 +61,14 @@
</div>
</li>
- <li class="more" v-if="thread_data.more_down">
+ <li class="more" v-if="threadData.more_down">
<studip-asset-img file="ajax-indicator-black.svg" width="20"></studip-asset-img>
</li>
</ol>
</div>
</div>
- <div class="writer" v-if="thread_data.thread_posting.commentable">
+ <div class="writer" v-if="threadData.thread_posting.commentable">
<studip-icon shape="blubber" size="30" role="info"></studip-icon>
<textarea :placeholder="writerTextareaPlaceholder"
@keyup.enter.exact="submit"
@@ -93,7 +93,8 @@
return {
already_loading_up: 0,
already_loading_down: 0,
- dragging: false
+ dragging: false,
+ threadData: this.thread_data
};
},
props: ['thread_data'],
@@ -102,9 +103,9 @@
if (!text || typeof text !== "string") {
text = $(this.$el).find(".writer textarea").val();
$(this.$el).find(".writer textarea").val("");
- if (this.thread_data.thread_posting.thread_id) {
+ if (this.threadData.thread_posting.thread_id) {
sessionStorage.removeItem(
- 'BlubberMemory-Writer-' + this.thread_data.thread_posting.thread_id
+ 'BlubberMemory-Writer-' + this.threadData.thread_posting.thread_id
);
}
}
@@ -126,14 +127,14 @@
let thread = this;
//AJAX-Request ...
- STUDIP.api.POST(`blubber/threads/${this.thread_data.thread_posting.thread_id}/comments`, {
+ STUDIP.api.POST(`blubber/threads/${this.threadData.thread_posting.thread_id}/comments`, {
data: {
content: text
}
}).then(data => {
// Check following state
- if (this.thread_data.notifications) {
- STUDIP.api.GET(`blubber/threads/${this.thread_data.thread_posting.thread_id}/follow`).then(followed => {
+ if (this.threadData.notifications) {
+ STUDIP.api.GET(`blubber/threads/${this.threadData.thread_posting.thread_id}/follow`).then(followed => {
jQuery('.followunfollow').toggleClass('unfollowed', !followed);
});
}
@@ -158,9 +159,9 @@
},
saveCommentToSession (event) {
let value = event.target.value;
- if (this.thread_data.thread_posting.thread_id) {
+ if (this.threadData.thread_posting.thread_id) {
sessionStorage.setItem(
- `BlubberMemory-Writer-${this.thread_data.thread_posting.thread_id}`,
+ `BlubberMemory-Writer-${this.threadData.thread_posting.thread_id}`,
value
);
}
@@ -195,19 +196,19 @@
this.$nextTick(() => {
STUDIP.Markup.element($(this.$el).find(`.comments > li[data-comment_id="${comment.comment_id}"]`));
});
- for (let i in this.thread_data.comments) {
- if (this.thread_data.comments[i].comment_id === comment.comment_id) {
- this.thread_data.comments[i].content = comment.content;
- this.thread_data.comments[i].html = comment.html;
+ for (let i in this.threadData.comments) {
+ if (this.threadData.comments[i].comment_id === comment.comment_id) {
+ this.threadData.comments[i].content = comment.content;
+ this.threadData.comments[i].html = comment.html;
return;
}
}
- this.thread_data.comments.push(comment);
+ this.threadData.comments.push(comment);
},
removeComment (comment_id) {
- this.thread_data.comments.forEach((comment, i) => {
+ this.threadData.comments.forEach((comment, i) => {
if (comment.comment_id === comment_id) {
- this.$delete(this.thread_data.comments, i);
+ this.$delete(this.threadData.comments, i);
}
});
},
@@ -295,7 +296,7 @@
}
let comment_id = $(li).data('comment_id');
let comment_data = null;
- this.thread_data.comments.forEach((comment, i) => {
+ this.threadData.comments.forEach((comment, i) => {
if (comment.comment_id === comment_id) {
comment_data = comment;
}
@@ -314,7 +315,7 @@
let comment_id = li.data('comment_id');
let content = li.find('textarea').val();
- thread.thread_data.comments.forEach((comment) => {
+ thread.threadData.comments.forEach((comment) => {
if (comment.comment_id === comment_id) {
comment.html = content;
}
@@ -322,13 +323,13 @@
li.find('.content').removeClass('editing');
- STUDIP.api.PUT(`blubber/threads/${this.thread_data.thread_posting.thread_id}/comments/${comment_id}`, {
+ STUDIP.api.PUT(`blubber/threads/${this.threadData.thread_posting.thread_id}/comments/${comment_id}`, {
data: {
content: content
},
}).done((output) => {
if (this.hasContent(output.content)) {
- thread.thread_data.comments.forEach((comment) => {
+ thread.threadData.comments.forEach((comment) => {
if (comment.comment_id === comment_id) {
comment.html = output.html;
comment.content = output.content;
@@ -359,10 +360,10 @@
},
toggleFollow () {
STUDIP.Blubber.followunfollow(
- this.thread_data.thread_posting.thread_id,
- !this.thread_data.followed
+ this.threadData.thread_posting.thread_id,
+ !this.threadData.followed
).done(state => {
- this.thread_data.followed = state;
+ this.threadData.followed = state;
});
},
hasContent (input) {
@@ -390,15 +391,15 @@
thread.$root.display_context_posting = top >= $(el).find('.all_content .thread_posting').height()
? 1
: 0;
- if (thread.thread_data.more_up && top < 1000 && !thread.already_loading_up) {
+ if (thread.threadData.more_up && top < 1000 && !thread.already_loading_up) {
thread.already_loading_up = 1;
- let earliest_mkdate = thread.thread_data.comments.reduce((min, comment) => {
+ let earliest_mkdate = thread.threadData.comments.reduce((min, comment) => {
return min === null ? comment.mkdate : Math.min(min, comment.mkdate);
}, null);
//load older comments
- STUDIP.api.GET(`blubber/threads/${thread.thread_data.thread_posting.thread_id}/comments`, {
+ STUDIP.api.GET(`blubber/threads/${thread.threadData.thread_posting.thread_id}/comments`, {
data: {
modifier: 'olderthan',
timestamp: earliest_mkdate,
@@ -407,7 +408,7 @@
}).done((data) => {
top = $(el).scrollTop();
thread.addComments(data.comments, false);
- thread.thread_data.more_up = data.more_up;
+ thread.threadData.more_up = data.more_up;
thread.$nextTick(function () {
//scroll to the position where we were:
let new_height = $(el).find(".all_content").height();
@@ -421,15 +422,15 @@
});
}
- if (thread.thread_data.more_down && (top > $(thread).find(".scrollable_area .all_content").height() - 1000) && !thread.already_loading_down) {
+ if (thread.threadData.more_down && (top > $(thread).find(".scrollable_area .all_content").height() - 1000) && !thread.already_loading_down) {
thread.already_loading_down = 1;
- let latest_mkdate = thread.thread_data.comments.reduce((max, comment) => {
+ let latest_mkdate = thread.threadData.comments.reduce((max, comment) => {
return Math.max(max, comment.mkdate);
}, null);
//load newer comments
- STUDIP.api.GET(`blubber/threads/${thread.thread_data.thread_posting.thread_id}/comments`, {
+ STUDIP.api.GET(`blubber/threads/${thread.threadData.thread_posting.thread_id}/comments`, {
data: {
modifier: 'newerthan',
timestamp: latest_mkdate,
@@ -437,7 +438,7 @@
}
}).done((data) => {
thread.addComments(data.comments, false);
- thread.thread_data.more_down = data.more_down;
+ thread.threadData.more_down = data.more_down;
}).always(() => {
thread.already_loading_down = 0;
});
@@ -448,7 +449,7 @@
},
mounted () { //when everything is initialized
this.$nextTick(function () {
- if (this.thread_data.comments.length > 0) {
+ if (this.threadData.comments.length > 0) {
this.scrollDown();
}
@@ -462,8 +463,8 @@
STUDIP.Markup.element(this);
});
- if (this.thread_data.thread_posting.thread_id) {
- let memory = sessionStorage.getItem(`BlubberMemory-Writer-${this.thread_data.thread_posting.thread_id}`);
+ if (this.threadData.thread_posting.thread_id) {
+ let memory = sessionStorage.getItem(`BlubberMemory-Writer-${this.threadData.thread_posting.thread_id}`);
if (memory) {
$(this.$el)
.find('.writer').addClass('filled')
@@ -474,24 +475,24 @@
},
computed: {
sortedComments () {
- return this.thread_data.comments.sort((a, b) => a.mkdate - b.mkdate);
+ return [...this.threadData.comments].sort((a, b) => a.mkdate - b.mkdate);
},
writerTextareaPlaceholder() {
- return this.hasContent(this.thread_data.thread_posting.content)
+ return this.hasContent(this.threadData.thread_posting.content)
? this.$gettext('Kommentar schreiben. Enter zum Abschicken.')
: this.$gettext('Nachricht schreiben. Enter zum Abschicken.');
}
},
updated () {
this.$nextTick(function () {
- if (this.thread_data.thread_posting.thread_id) {
- let memory = sessionStorage.getItem('BlubberMemory-Writer-' + this.thread_data.thread_posting.thread_id);
+ if (this.threadData.thread_posting.thread_id) {
+ let memory = sessionStorage.getItem('BlubberMemory-Writer-' + this.threadData.thread_posting.thread_id);
$(this.$el).find('.writer textarea').val(memory);
}
});
},
watch: {
- thread_data (new_data, old_data) {
+ threadData (new_data, old_data) {
if (new_data.thread_posting.thread_id !== old_data.thread_posting.thread_id) {
//if the thread got reloaded by a new thread
//markup contents
diff --git a/resources/vue/components/BlubberThreadWidget.vue b/resources/vue/components/BlubberThreadWidget.vue
index 2a2de1c..0606eb8 100644
--- a/resources/vue/components/BlubberThreadWidget.vue
+++ b/resources/vue/components/BlubberThreadWidget.vue
@@ -34,7 +34,8 @@
data () {
return {
display_more_down: this.more_down,
- already_loading_down: 0
+ already_loading_down: 0,
+ allThreads: this.threads
};
},
methods: {
@@ -50,11 +51,11 @@
return STUDIP.URLHelper.getURL(`dispatch.php/blubber/index/${thread_id}`);
},
addThread (thread) {
- let thread_ids = this.threads.map((t) => t.thread_id);
+ let thread_ids = this.allThreads.map((t) => t.thread_id);
if (thread_ids.indexOf(thread.thread_id) !== -1) {
return;
}
- this.threads.push(thread);
+ this.allThreads.push(thread);
}
},
directives: {
@@ -104,7 +105,7 @@
},
computed: {
sortedThreads () {
- return this.threads.sort((a, b) => {
+ return [...this.allThreads].sort((a, b) => {
return b.timestamp - a.timestamp
|| b.mkdate - a.mkdate
|| b.name.localeCompare(a.name);
diff --git a/resources/vue/components/CacheAdministration.vue b/resources/vue/components/CacheAdministration.vue
index 14e1d53..af3d461 100644
--- a/resources/vue/components/CacheAdministration.vue
+++ b/resources/vue/components/CacheAdministration.vue
@@ -55,9 +55,11 @@ export default {
},
currentConfig: {
type: Object,
- default: {
- component: null,
- props: []
+ default() {
+ return {
+ component: null,
+ props: []
+ };
}
}
},
diff --git a/resources/vue/components/Datetimepicker.vue b/resources/vue/components/Datetimepicker.vue
index 3ec930c..87f6dfd 100644
--- a/resources/vue/components/Datetimepicker.vue
+++ b/resources/vue/components/Datetimepicker.vue
@@ -38,7 +38,7 @@ export default {
}
},
mounted () {
- let value = parseInt(this.value, 10) !== NaN ? parseInt(this.value, 10) : this.value;
+ let value = !isNaN(parseInt(this.value, 10)) ? parseInt(this.value, 10) : this.value;
if (Number.isInteger(value)) {
let date = new Date(value * 1000);
let formatted_date =
diff --git a/resources/vue/components/EditableList.vue b/resources/vue/components/EditableList.vue
index 8b22422..e35d1d6 100644
--- a/resources/vue/components/EditableList.vue
+++ b/resources/vue/components/EditableList.vue
@@ -18,11 +18,15 @@
<translate>Oder aus Liste auswählen:</translate>
<select @change="quickselect" @keydown="navigate_or_select">
<option value=""><translate>Direkt auswählen ...</translate></option>
- <template v-for="opt in selectable">
- <optgroup v-if="opt.label && opt.options" :label="opt.label">
- <option v-for="option in opt.options" :disabled="isSelected(option.value)" :value="JSON.stringify({value: option.value, name: option.name})">{{ option.name + (isSelected(option.value) ? ' ✓' : '') }}</option>
+ <template v-for="(opt, idx) in selectable">
+ <optgroup v-if="opt.label && opt.options" :label="opt.label" :key="idx">
+ <option v-for="(option, index) in opt.options" :disabled="isSelected(option.value)" :value="JSON.stringify({value: option.value, name: option.name})" :key="index">
+ {{ option.name + (isSelected(option.value) ? ' ✓' : '') }}
+ </option>
</optgroup>
- <option v-else :disabled="isSelected(opt.value)" @click="quicksearch" :value="JSON.stringify({value: opt.value, name: opt.name})">{{ opt.name + (isSelected(option.value) ? ' ✓' : '') }}</option>
+ <option v-else :disabled="isSelected(opt.value)" @click="quicksearch" :value="JSON.stringify({value: opt.value, name: opt.name})" :key="idx">
+ {{ opt.name + (isSelected(option.value) ? ' ✓' : '') }}
+ </option>
</template>
</select>
@@ -52,13 +56,14 @@ export default {
category_order: {
type: Array,
required: false,
- default: []
+ default: () => [],
}
},
data () {
return {
resort: false, //this is just for triggering the computed property sortedItems to be sorted again
- preventChangeOfQuickselect: false
+ preventChangeOfQuickselect: false,
+ allItems: this.items
};
},
methods: {
@@ -68,16 +73,8 @@ export default {
icon = id.split('__')[1];
id = id.split('__')[0];
}
- let insert = true;
- for (let i in this.items) {
- if (this.items[i].value === id) {
- insert = false;
- break;
- }
- }
-
- if (insert) {
- this.items.push({
+ if (!this.allItems.find(item => item.value === id)) {
+ this.allItems.push({
value: id,
name: name,
icon: icon,
@@ -143,22 +140,19 @@ export default {
},
computed: {
sortedItems () {
- let v = this;
- let i = this.resort;
- let items = this.items.sort(function (a, b) {
+ return [...this.items].sort((a, b) => {
if (a.icon === b.icon) {
return a.name.localeCompare(b.name);
} else {
let a_icon = a.icon || '';
let b_icon = b.icon || '';
- if (v.category_order.indexOf(a_icon) > -1 && v.category_order.indexOf(b_icon) > -1) {
- return v.category_order.indexOf(a_icon) < v.category_order.indexOf(b_icon) ? -1 : 1;
+ if (this.category_order.indexOf(a_icon) > -1 && this.category_order.indexOf(b_icon) > -1) {
+ return this.category_order.indexOf(a_icon) < this.category_order.indexOf(b_icon) ? -1 : 1;
} else {
return a_icon.localeCompare(b_icon);
}
}
});
- return items;
}
},
mounted () {
diff --git a/resources/vue/components/FilesTable.vue b/resources/vue/components/FilesTable.vue
index 15f2d49..e58d214 100644
--- a/resources/vue/components/FilesTable.vue
+++ b/resources/vue/components/FilesTable.vue
@@ -15,9 +15,7 @@
{{ breadcrumbs[0].name }}
</span>
</a>
- <span v-for="(breadcrumb, index) in breadcrumbs"
- :key="breadcrumb.folder_id"
- v-if="index > 0">
+ <span v-for="breadcrumb in breadcrumbs.slice(1)" :key="breadcrumb.folder_id">
/<a :href="breadcrumb.url">
{{ breadcrumb.name }}
</a>
@@ -36,8 +34,7 @@
<col v-if="showdownloads" style="width: 100px" class="responsive-hidden">
<col style="width: 150px" class="responsive-hidden">
<col style="width: 120px" class="responsive-hidden">
- <col v-if="topfolder.additionalColumns"
- v-for="(name, index) in topfolder.additionalColumns"
+ <col v-for="(name, index) in additionalColumns"
:key="index"
data-filter-ignore
class="responsive-hidden">
@@ -81,8 +78,7 @@
{{ $gettext('Datum') }}
</a>
</th>
- <th v-if="topfolder.additionalColumns"
- v-for="(name, index) in topfolder.additionalColumns"
+ <th v-for="(name, index) in additionalColumns"
:key="index"
@click="sort(index)"
class="responsive-hidden"
@@ -112,7 +108,8 @@
<tbody class="subfolders" v-if="displayedFolders.length > 0">
<tr v-for="folder in displayedFolders"
:id="'row_folder_' + folder.id "
- :data-permissions="folder.permissions">
+ :data-permissions="folder.permissions"
+ :key="folder.id">
<td v-if="show_bulk_actions">
<studip-proxied-checkbox
name="ids[]"
@@ -146,12 +143,12 @@
<td class="responsive-hidden" style="white-space: nowrap;">
<studip-date-time :timestamp="folder.chdate" :relative="true"></studip-date-time>
</td>
- <template v-if="topfolder.additionalColumns"
- v-for="(name, index) in topfolder.additionalColumns">
+ <template v-for="(name, index) in additionalColumns">
<td v-if="folder.additionalColumns && folder.additionalColumns[index] && folder.additionalColumns[index].html"
class="responsive-hidden"
- v-html="folder.additionalColumns[index].html"></td>
- <td v-else class="responsive-hidden"></td>
+ v-html="folder.additionalColumns[index].html"
+ :key="index"></td>
+ <td v-else class="responsive-hidden" :key="index"></td>
</template>
<td class="actions" v-html="folder.actions">
</td>
@@ -162,7 +159,8 @@
:class="file.new ? 'new' : ''"
:id="'fileref_' + file.id"
role="row"
- :data-permissions="getPermissions(file)">
+ :data-permissions="getPermissions(file)"
+ :key="file.id">
<td v-if="show_bulk_actions">
<studip-proxied-checkbox
name="ids[]"
@@ -209,12 +207,12 @@
<td data-sort-value="file.chdate" class="responsive-hidden" style="white-space: nowrap;">
<studip-date-time :timestamp="file.chdate" :relative="true"></studip-date-time>
</td>
- <template v-if="topfolder.additionalColumns"
- v-for="(name, index) in topfolder.additionalColumns">
+ <template v-for="(name, index) in additionalColumns">
<td v-if="file.additionalColumns && file.additionalColumns[index] && file.additionalColumns[index].html"
class="responsive-hidden"
- v-html="file.additionalColumns[index].html"></td>
- <td v-else class="responsive-hidden"></td>
+ v-html="file.additionalColumns[index].html"
+ :key="index"></td>
+ <td v-else class="responsive-hidden" :key="index"></td>
</template>
<td class="actions" v-html="file.actions">
</td>
@@ -299,6 +297,8 @@ export default {
selectedIds: [undefined], // Includes invalid value to trigger watch on mounted
sortedBy: this.initial_sort.sortedBy,
sortDirection: this.initial_sort.sortDirection,
+ allFiles: this.files,
+ allFolders: this.folders,
filter: ''
};
},
@@ -318,10 +318,10 @@ export default {
return classes;
},
removeFile (id) {
- this.files = this.files.filter(file => file.id != id)
+ this.allFiles = this.allFiles.filter(file => file.id != id)
},
removeFolder (id) {
- this.folders = this.folders.filter(folder => folder.id != id)
+ this.allFolders = this.allFolders.filter(folder => folder.id != id)
},
sortArray (array) {
if (!array.length) {
@@ -344,7 +344,7 @@ export default {
}
// Additional sorting
- if (this.topfolder.additionalColumns.hasOwnProperty(this.sortedBy) && arrayHasKey) {
+ if (this.topfolder.additionalColumns[this.sortedBy] !== undefined && arrayHasKey) {
const is_string = array.some(item => {
return typeof item.additionalColumns[this.sortedBy].order === "string"
&& !isNaN(parseFloat(item.additionalColumns[this.sortedBy].order));
@@ -379,7 +379,7 @@ export default {
let highlighted = sanitizeHTML(string);
if (this.needleForFilter.length > 0) {
// Escape needle for regexp, see https://stackoverflow.com/a/3561711
- const pattern = this.needleForFilter.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
+ const pattern = this.needleForFilter.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&')
const regExp = new RegExp(pattern, 'gi');
highlighted = highlighted.replace(regExp, '<span class="filter-match">$&</span>');
}
@@ -392,6 +392,9 @@ export default {
+ (this.showdownloads ? 1 : 0)
+ Object.keys(this.topfolder.additionalColumns).length;
},
+ additionalColumns () {
+ return this.topfolder.additionalColumns || [];
+ },
sortedFiles () {
return this.sortArray(this.files);
},
@@ -402,7 +405,7 @@ export default {
return [].concat(this.files.map(file => file.id)).concat(this.folders.map(folder => folder.id));
},
displayedFiles () {
- let files = [].concat(this.files);
+ let files = [...this.allFiles];
if (this.needleForFilter.length > 0) {
files = files.filter(file => {
return this.valueMatchesFilter(file.name)
@@ -412,7 +415,7 @@ export default {
return this.sortArray(files);
},
displayedFolders () {
- let folders = [].concat(this.folders);
+ let folders = [...this.allFolders];
if (this.needleForFilter.length > 0) {
folders = folders.filter(folder => {
return this.valueMatchesFilter(folder.name)
diff --git a/resources/vue/components/I18nTextarea.vue b/resources/vue/components/I18nTextarea.vue
index 084cdfb..76a025c 100644
--- a/resources/vue/components/I18nTextarea.vue
+++ b/resources/vue/components/I18nTextarea.vue
@@ -1,15 +1,13 @@
<template>
<div class="i18n_group" v-if="languages.length > 1">
<div class="i18n"
- v-for="language in languages"
- v-if="(selectedLanguage !== null) && (language.id === selectedLanguage.id)"
- :data-lang="language.name"
- :data-icon="'url(' + assetsURL + 'images/languages/' + language.picture + ')'">
+ :data-lang="primaryLanguage.name"
+ :data-icon="'url(' + assetsURL + 'images/languages/' + primaryLanguage.picture + ')'">
<input type=text
ref="inputfield"
:name="nameOfInput(language.id)"
- v-model="values[selectedLanguage.id]"
- :required="required && defaultLanguage === language.id"
+ v-model="values[primaryLanguage.id]"
+ :required="required && defaultLanguage === primaryLanguage.id"
v-bind="$attrs"
v-on="$listeners"
v-if="type === 'text'">
@@ -19,34 +17,36 @@
v-on="$listeners"
v-model="values[language.id]"
:required="required && defaultLanguage === language.id"
- v-else-if="type === 'textarea'">{{ values[language.id] }}</textarea>
+ v-else-if="type === 'textarea'"></textarea>
<studip-wysiwyg :name="nameOfInput(language.id)"
ref="inputfield"
v-model="values[selectedLanguage.id]"
v-bind="$attrs"
v-on="$listeners"
- :required="required && defaultLanguage === language.id"
+ :required="required && defaultLanguage === primaryLanguage.id"
v-else-if="type === 'wysiwyg' && !wysiwyg_disabled"></studip-wysiwyg>
<textarea-with-toolbar :name="nameOfInput(language.id)"
ref="inputfield"
v-else
- v-model="values[selectedLanguage.id]"
+ v-model="values[primaryLanguage.id]"
v-bind="$attrs"
- :required="required && defaultLanguage === language.id"
+ :required="required && defaultLanguage === primaryLanguage.id"
v-on="$listeners"></textarea-with-toolbar>
</div>
<input type="hidden"
- v-for="language in languages"
- v-if="(selectedLanguage !== null) && (language.id !== selectedLanguage.id)"
+ v-for="language in secondaryLanguages"
v-model="values[language.id]"
:required="required && defaultLanguage === language.id"
- :name="nameOfInput(language.id)">
+ :name="nameOfInput(language.id)"
+ :key="language.id">
<select class="i18n"
tabindex="0"
@change="selectLanguage"
:aria-label="$gettext('Sprache des Textfeldes auswählen.')"
:style="'background-image: url(' + assetsURL + 'images/languages/' + selectedLanguage.picture + ')'">
- <option v-for="language in languages" :value="language.id">{{language.name}}</option>
+ <option v-for="language in languages" :value="language.id" :key="language.id">
+ {{language.name}}
+ </option>
</select>
</div>
<div v-else>
@@ -130,10 +130,11 @@ export default {
this.selectedLanguage = this.languages[i];
break;
}
- let jsonvalue = false;
+ let jsonvalue;
try {
jsonvalue = JSON.parse(this.value);
} catch (except) {
+ jsonvalue = false;
}
if (jsonvalue !== false) {
this.values = jsonvalue;
@@ -179,6 +180,12 @@ export default {
}
}
return languages;
+ },
+ primaryLanguage () {
+ return this.languages.find(language => language.id === this.selectedLanguage.id);
+ },
+ secondaryLanguages () {
+ return this.languages.filter(language => language.id !== this.selectedLanguage.id);
}
},
inheritAttrs: false,
diff --git a/resources/vue/components/MyCoursesColorPicker.vue b/resources/vue/components/MyCoursesColorPicker.vue
index ecf24a7..368ae5f 100644
--- a/resources/vue/components/MyCoursesColorPicker.vue
+++ b/resources/vue/components/MyCoursesColorPicker.vue
@@ -1,6 +1,6 @@
<template>
<ul class="my-courses-color-picker">
- <li v-for="(i, index) in color_count" :id="i" :class="getCSSClasses(index)">
+ <li v-for="(i, index) in color_count" :id="i" :class="getCSSClasses(index)" :key="index">
<a @click="selectColor(index)" :title="getTitle(i, index)">
{{ getTitle(i) }}
</a>
diff --git a/resources/vue/components/MyCoursesNavigation.vue b/resources/vue/components/MyCoursesNavigation.vue
index f3dbad2..739668c 100644
--- a/resources/vue/components/MyCoursesNavigation.vue
+++ b/resources/vue/components/MyCoursesNavigation.vue
@@ -1,6 +1,6 @@
<template>
<ul class="my-courses-navigation" v-if="navigationLength > 0">
- <li v-for="nav in navigation" class="my-courses-navigation-item" :class="nav.class">
+ <li v-for="(nav, index) in navigation" class="my-courses-navigation-item" :class="nav.class" :key="index">
<a v-if="nav" :href="nav.url" v-bind="nav.attr">
<studip-icon :shape="nav.icon.shape" :role="nav.icon.role" :size="iconSize"></studip-icon>
</a>
diff --git a/resources/vue/components/MyCoursesTables.vue b/resources/vue/components/MyCoursesTables.vue
index c542e3d..0a5abad 100644
--- a/resources/vue/components/MyCoursesTables.vue
+++ b/resources/vue/components/MyCoursesTables.vue
@@ -36,7 +36,7 @@
</th>
<th v-if="!responsiveDisplay" class="dont-hide" colspan="2"></th>
</tr>
- <tr v-for="course in getOrderedCourses(subgroup.ids)" :data-course-id="course.id" :class="getCourseClasses(course)">
+ <tr v-for="course in getOrderedCourses(subgroup.ids)" :data-course-id="course.id" :class="getCourseClasses(course)" :key="course.id">
<td :class="`gruppe${course.group}`"></td>
<td :class="{'subcourse-indented': isChild(course)}">
<span :style="{backgroundImage: `url(${course.avatar}`}" class="my-courses-avatar course-avatar-small" :title="course.name" alt=""></span>
diff --git a/resources/vue/components/MyCoursesTiles.vue b/resources/vue/components/MyCoursesTiles.vue
index 28ff6c6..71c5b64 100644
--- a/resources/vue/components/MyCoursesTiles.vue
+++ b/resources/vue/components/MyCoursesTiles.vue
@@ -1,7 +1,7 @@
<template>
<div class="my-courses my-courses--tiles">
- <template v-for="group in groups">
- <div class="group-label">{{ group.name }}</div>
+ <template v-for="(group, index) in groups">
+ <div class="group-label" :key="index">{{ group.name }}</div>
<article class="studip" v-for="subgroup in group.data" :key="subgroup.id" :class="getGroupCssClasses(subgroup)">
<header v-if="subgroup.label">
<h1>
@@ -10,11 +10,11 @@
</header>
<section class="studip-grid">
<template v-for="course in getOrderedCourses(subgroup.ids)">
- <div class="course-group-label" v-if="isParent(course)">
+ <div class="course-group-label" v-if="isParent(course)" :key="course.id">
{{ getCourseName(course, getConfig('sem_number')) }}
</div>
- <article class="studip-grid-element" :data-course-id="course.id" :class="getCourseCssClasses(course)">
+ <article class="studip-grid-element" :data-course-id="course.id" :class="getCourseCssClasses(course)" :key="course.id">
<header class="tiles-grid-element-header">
<span class="tiles-grid-element-options">
<studip-action-menu :items="getActionMenuForCourse(course, true)"
diff --git a/resources/vue/components/StudipDialog.vue b/resources/vue/components/StudipDialog.vue
index 242bc23..603b8b0 100644
--- a/resources/vue/components/StudipDialog.vue
+++ b/resources/vue/components/StudipDialog.vue
@@ -190,6 +190,7 @@ export default {
if (this.message) {
return this.$gettext('Information');
}
+ return '';
},
dialogWidth() {
return this.currentWidth ? (this.currentWidth - dialogPadding * 4) + 'px' : 'unset';
@@ -217,7 +218,7 @@ export default {
this.left = 5;
this.currentWidth = window.innerWidth - 16;
}
-
+
this.top = (window.innerHeight - this.currentHeight) / 2;
this.footerHeight = this.$refs.footer.offsetHeight;
},
diff --git a/resources/vue/components/StudipFileSize.vue b/resources/vue/components/StudipFileSize.vue
index 46a0699..4b26c15 100644
--- a/resources/vue/components/StudipFileSize.vue
+++ b/resources/vue/components/StudipFileSize.vue
@@ -31,6 +31,8 @@
let rel = (this.size / 1024 / 1024 / 1024 / 1024).toFixed(1);
return rel + " TB";
}
+
+ return this.size;
}
}
}
diff --git a/resources/vue/components/StudipMessageBox.vue b/resources/vue/components/StudipMessageBox.vue
index 471225e..0e2fcb7 100644
--- a/resources/vue/components/StudipMessageBox.vue
+++ b/resources/vue/components/StudipMessageBox.vue
@@ -5,14 +5,14 @@
<span>{{ $gettext('Detailanzeige umschalten') }}</span>
</a>
<a v-if="!hideClose" class="close" href="" :title="$gettext('Nachrichtenbox schließen')" @click.prevent="closed = true">
- <span>{{ $gettext('Nachrichtenbox schließen') }}</span>
+ <span>{{ $gettext('Nachrichtenbox schließen') }}</span>
</a>
</div>
<slot></slot>
<div v-if="showDetails" class="messagebox_details">
<slot name="details">
<ul>
- <li v-for="detail in details" v-html="detail"></li>
+ <li v-for="(detail, index) in details" v-html="detail" :key="index"></li>
</ul>
</slot>
</div>
@@ -32,7 +32,7 @@ export default {
},
details: {
type: Array,
- default: [],
+ default: () => [],
},
hideDetails: {
type: Boolean,
diff --git a/resources/vue/components/courseware/CoursewareAccordionContainer.vue b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
index 7d9f762..8e4d098 100644
--- a/resources/vue/components/courseware/CoursewareAccordionContainer.vue
+++ b/resources/vue/components/courseware/CoursewareAccordionContainer.vue
@@ -67,7 +67,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="option">
@@ -241,7 +241,7 @@ export default {
return null;
},
updateContent(blockAdder) {
- if(blockAdder.hasOwnProperty('container') && blockAdder.container.id === this.container.id) {
+ if (blockAdder.container !== undefined && blockAdder.container.id === this.container.id) {
this.initCurrentData();
}
}
diff --git a/resources/vue/components/courseware/CoursewareActionWidget.vue b/resources/vue/components/courseware/CoursewareActionWidget.vue
index 2db5c2f..fa79d12 100644
--- a/resources/vue/components/courseware/CoursewareActionWidget.vue
+++ b/resources/vue/components/courseware/CoursewareActionWidget.vue
@@ -63,7 +63,6 @@
</template>
<script>
-import StudipIcon from './../StudipIcon.vue';
import SidebarWidget from '../SidebarWidget.vue';
import CoursewareExport from '@/vue/mixins/courseware/export.js';
import { mapActions, mapGetters } from 'vuex';
@@ -72,7 +71,6 @@ export default {
name: 'courseware-action-widget',
props: ['structuralElement', 'canVisit'],
components: {
- StudipIcon,
SidebarWidget,
},
mixins: [CoursewareExport],
diff --git a/resources/vue/components/courseware/CoursewareBiographyAchievementsBlock.vue b/resources/vue/components/courseware/CoursewareBiographyAchievementsBlock.vue
index 7a3ce6d..532352f 100755
--- a/resources/vue/components/courseware/CoursewareBiographyAchievementsBlock.vue
+++ b/resources/vue/components/courseware/CoursewareBiographyAchievementsBlock.vue
@@ -81,7 +81,6 @@
import CoursewareDefaultBlock from './CoursewareDefaultBlock.vue';
import { mapActions } from 'vuex';
import { blockMixin } from './block-mixin.js';
-import StudipIcon from '../StudipIcon.vue';
import StudipWysiwyg from '../StudipWysiwyg.vue';
export default {
@@ -89,7 +88,6 @@ export default {
mixins: [blockMixin],
components: {
CoursewareDefaultBlock,
- StudipIcon,
StudipWysiwyg,
},
props: {
diff --git a/resources/vue/components/courseware/CoursewareBiographyGoalsBlock.vue b/resources/vue/components/courseware/CoursewareBiographyGoalsBlock.vue
index 4ff944b..5938a28 100755
--- a/resources/vue/components/courseware/CoursewareBiographyGoalsBlock.vue
+++ b/resources/vue/components/courseware/CoursewareBiographyGoalsBlock.vue
@@ -85,6 +85,8 @@ export default {
case 'professional':
return this.$gettext('Berufliches Ziel');
}
+
+ throw new Error('Undefined data type ' + this.currentData.type);
},
},
mounted() {
diff --git a/resources/vue/components/courseware/CoursewareBiographyPersonalInformationBlock.vue b/resources/vue/components/courseware/CoursewareBiographyPersonalInformationBlock.vue
index e8ee5b4..14ba1be 100755
--- a/resources/vue/components/courseware/CoursewareBiographyPersonalInformationBlock.vue
+++ b/resources/vue/components/courseware/CoursewareBiographyPersonalInformationBlock.vue
@@ -75,14 +75,12 @@
import CoursewareDefaultBlock from './CoursewareDefaultBlock.vue';
import { mapActions } from 'vuex';
import { blockMixin } from './block-mixin.js';
-import StudipIcon from '../StudipIcon.vue';
export default {
name: 'courseware-biography-personal-information-block',
mixins: [blockMixin],
components: {
CoursewareDefaultBlock,
- StudipIcon,
},
props: {
block: Object,
diff --git a/resources/vue/components/courseware/CoursewareChartBlock.vue b/resources/vue/components/courseware/CoursewareChartBlock.vue
index 4329659..96726bf 100644
--- a/resources/vue/components/courseware/CoursewareChartBlock.vue
+++ b/resources/vue/components/courseware/CoursewareChartBlock.vue
@@ -61,7 +61,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="{name, rgb}">
diff --git a/resources/vue/components/courseware/CoursewareContentBookmarks.vue b/resources/vue/components/courseware/CoursewareContentBookmarks.vue
index 329289c..8534542 100644
--- a/resources/vue/components/courseware/CoursewareContentBookmarks.vue
+++ b/resources/vue/components/courseware/CoursewareContentBookmarks.vue
@@ -62,6 +62,7 @@ export default {
return bookmark.relationships.course.data.id === this.bookmarkFilter;
});
}
+ return [];
}
},
methods: {
diff --git a/resources/vue/components/courseware/CoursewareContentOverviewElements.vue b/resources/vue/components/courseware/CoursewareContentOverviewElements.vue
index c23e6d6..0e6a87f 100644
--- a/resources/vue/components/courseware/CoursewareContentOverviewElements.vue
+++ b/resources/vue/components/courseware/CoursewareContentOverviewElements.vue
@@ -193,7 +193,7 @@
><studip-icon shape="arr_1down" size="10"
/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="{ name, hex }">
@@ -540,7 +540,7 @@ export default {
const ownerId = element.relationships.owner.data.id;
const owner = this.userById({ id: ownerId });
- return owner.attributes['formatted-name'];
+ return owner.attributes['formatted-name'];
},
addElement() {
this.setShowOverviewElementAddDialog(true);
diff --git a/resources/vue/components/courseware/CoursewareContentPermissions.vue b/resources/vue/components/courseware/CoursewareContentPermissions.vue
index 2264072..a2de339 100755
--- a/resources/vue/components/courseware/CoursewareContentPermissions.vue
+++ b/resources/vue/components/courseware/CoursewareContentPermissions.vue
@@ -233,6 +233,7 @@ export default {
this.userPermsWriteUsers = this.element.attributes['write-approval'].users;
}
+ /* eslint-disable no-await-in-loop */
for (const user_perm_obj of this.userPermsReadUsers) {
let userObj = await this.getUser(user_perm_obj.id);
let writePerm = this.userPermsWriteUsers.some(user_write_perm => user_write_perm.id === user_perm_obj.id) ? true : false;
diff --git a/resources/vue/components/courseware/CoursewareDefaultBlock.vue b/resources/vue/components/courseware/CoursewareDefaultBlock.vue
index 5df64c9..b3023f5 100644
--- a/resources/vue/components/courseware/CoursewareDefaultBlock.vue
+++ b/resources/vue/components/courseware/CoursewareDefaultBlock.vue
@@ -79,14 +79,10 @@
</template>
<script>
-import CoursewareBlockComments from './CoursewareBlockComments.vue';
import CoursewareBlockEdit from './CoursewareBlockEdit.vue';
import CoursewareBlockExportOptions from './CoursewareBlockExportOptions.vue';
-import CoursewareBlockFeedback from './CoursewareBlockFeedback.vue';
import CoursewareBlockInfo from './CoursewareBlockInfo.vue';
import CoursewareBlockActions from './CoursewareBlockActions.vue';
-import CoursewareTabs from './CoursewareTabs.vue';
-import CoursewareTab from './CoursewareTab.vue';
import StudipDialog from '../StudipDialog.vue';
import StudipIcon from '../StudipIcon.vue';
import { blockMixin } from './block-mixin.js';
@@ -97,14 +93,10 @@ export default {
name: 'courseware-default-block',
mixins: [blockMixin],
components: {
- CoursewareBlockComments,
CoursewareBlockEdit,
CoursewareBlockExportOptions,
- CoursewareBlockFeedback,
CoursewareBlockActions,
CoursewareBlockInfo,
- CoursewareTabs,
- CoursewareTab,
StudipDialog,
StudipIcon,
CoursewareBlockDiscussion,
diff --git a/resources/vue/components/courseware/CoursewareDefaultContainer.vue b/resources/vue/components/courseware/CoursewareDefaultContainer.vue
index 962febb..5822072 100644
--- a/resources/vue/components/courseware/CoursewareDefaultContainer.vue
+++ b/resources/vue/components/courseware/CoursewareDefaultContainer.vue
@@ -137,7 +137,6 @@ export default {
deleteContainer: 'deleteContainer',
lockObject: 'lockObject',
unlockObject: 'unlockObject',
- companionInfo: 'companionInfo',
}),
async displayEditDialog() {
await this.loadContainer({ id: this.container.id, options: { include: 'edit-blocker' } });
diff --git a/resources/vue/components/courseware/CoursewareDialogCardsBlock.vue b/resources/vue/components/courseware/CoursewareDialogCardsBlock.vue
index 022590b..b051aec 100644
--- a/resources/vue/components/courseware/CoursewareDialogCardsBlock.vue
+++ b/resources/vue/components/courseware/CoursewareDialogCardsBlock.vue
@@ -11,7 +11,7 @@
>
<template #content>
<div class="cw-block-dialog-cards-content">
- <button
+ <button
class="cw-dialogcards-prev cw-dialogcards-navbutton"
:class="{'cw-dialogcards-prev-disabled': hasNoPerv}"
@click="prevCard"
@@ -69,7 +69,7 @@
:name="$gettext('Karte') + ' ' + (index + 1).toString()"
:selected="index === 0"
canBeEmpty
- >
+ >
<form class="default" @submit.prevent="">
<label>
<translate>Bild Vorderseite</translate>:
@@ -118,7 +118,6 @@ import CoursewareTabs from './CoursewareTabs.vue';
import CoursewareTab from './CoursewareTab.vue';
import { blockMixin } from './block-mixin.js';
import { mapActions } from 'vuex';
-import StudipIcon from '../StudipIcon.vue';
export default {
name: 'courseware-dialog-cards-block',
@@ -128,7 +127,6 @@ export default {
CoursewareFileChooser,
CoursewareTabs,
CoursewareTab,
- StudipIcon,
},
props: {
block: Object,
diff --git a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
index 8a5bc6c..292ad60 100644
--- a/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
+++ b/resources/vue/components/courseware/CoursewareHeadlineBlock.vue
@@ -68,7 +68,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="{name, hex}">
@@ -85,7 +85,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="option">
@@ -108,7 +108,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="{name, hex}">
@@ -138,7 +138,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="{name, hex}">
diff --git a/resources/vue/components/courseware/CoursewareImageMapBlock.vue b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
index f097e78..597213b 100644
--- a/resources/vue/components/courseware/CoursewareImageMapBlock.vue
+++ b/resources/vue/components/courseware/CoursewareImageMapBlock.vue
@@ -72,7 +72,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="{name, rgba}">
@@ -417,6 +417,9 @@ export default {
this.currentShapes.forEach((value, key) => {
let shape = value;
let area = {};
+ let coords = '';
+ let x = 0;
+ let y = 0;
area.id = 'shape-' + key;
switch (shape.type) {
@@ -425,9 +428,6 @@ export default {
area.coords = shape.data.centerX + ', ' + shape.data.centerY + ', ' + shape.data.radius;
break;
case 'ellipse':
- let coords = '';
- let x = 0;
- let y = 0;
for (let theta = 0; theta < 2 * Math.PI; theta += (2 * Math.PI) / 20) {
x = parseInt(shape.data.X) + Math.round(parseInt(shape.data.radiusX) * Math.cos(theta));
y = parseInt(shape.data.Y) + Math.round(parseInt(shape.data.radiusY) * Math.sin(theta));
@@ -438,10 +438,10 @@ export default {
break;
case 'rect':
case 'text':
- let x2 = parseInt(shape.data.X) + parseInt(shape.data.width);
- let y2 = parseInt(shape.data.Y) + parseInt(shape.data.height);
+ x = parseInt(shape.data.X) + parseInt(shape.data.width);
+ y = parseInt(shape.data.Y) + parseInt(shape.data.height);
area.shape = 'rect';
- area.coords = shape.data.X + ', ' + shape.data.Y + ', ' + x2 + ', ' + y2;
+ area.coords = shape.data.X + ', ' + shape.data.Y + ', ' + x + ', ' + y;
break;
}
area.title = shape.title;
diff --git a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
index 05d5d2f..2fc29b4 100644
--- a/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
+++ b/resources/vue/components/courseware/CoursewareKeyPointBlock.vue
@@ -40,7 +40,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="{name, hex}">
@@ -58,7 +58,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="option">
@@ -171,6 +171,7 @@ export default {
return 'status-yellow';
case 'blue':
+ default:
return 'clickable';
}
}
diff --git a/resources/vue/components/courseware/CoursewareManagerCopySelector.vue b/resources/vue/components/courseware/CoursewareManagerCopySelector.vue
index 3c22dcd..084e9a2 100644
--- a/resources/vue/components/courseware/CoursewareManagerCopySelector.vue
+++ b/resources/vue/components/courseware/CoursewareManagerCopySelector.vue
@@ -28,7 +28,7 @@
</ul>
</li>
</ul>
- <courseware-companion-box
+ <courseware-companion-box
v-if="!hasRemoteCid && semesterMap.length === 0"
:msgCompanion="$gettext('Es wurden keine Veranstaltung mit Courseware-Inhalten gefunden.')"
mood="sad"
@@ -113,7 +113,7 @@ export default {
return this.remoteCid !== '';
},
loadedCourses() {
- return this.courses.sort((a, b) => a.attributes.title > b.attributes.title);
+ return [...this.courses].sort((a, b) => a.attributes.title > b.attributes.title);
}
},
methods: {
@@ -218,7 +218,7 @@ export default {
elementId: elementId,
migrate: true
});
- } catch(error) {
+ } catch(error) {
console.debug(error);
this.copyAllInProgressText = this.$gettext('Beim Kopiervorgang sind Fehler aufgetreten.');
}
diff --git a/resources/vue/components/courseware/CoursewareManagerElement.vue b/resources/vue/components/courseware/CoursewareManagerElement.vue
index 2bd892c..bae3725 100644
--- a/resources/vue/components/courseware/CoursewareManagerElement.vue
+++ b/resources/vue/components/courseware/CoursewareManagerElement.vue
@@ -471,6 +471,9 @@ export default {
if(!this.insertingInProgress) {
this.insertingInProgress = true;
if (source === 'self') {
+ block.relationships.container.data.id = this.filingData.parentItem.id;
+ block.attributes.position = this.filingData.parentItem.relationships.blocks.data.length + 1;
+
let sourceContainer = await this.containerById({id: block.relationships.container.data.id});
sourceContainer.attributes.payload.sections.forEach(section => {
let index = section.blocks.indexOf(block.id);
@@ -494,8 +497,6 @@ export default {
});
await this.unlockObject({id: destinationContainer.id, type: 'courseware-containers'});
- block.relationships.container.data.id = this.filingData.parentItem.id;
- block.attributes.position = this.filingData.parentItem.relationships.blocks.data.length + 1;
await this.lockObject({id: block.id, type: 'courseware-blocks'});
await this.updateBlock({
block: block,
diff --git a/resources/vue/components/courseware/CoursewareManagerLinkSelector.vue b/resources/vue/components/courseware/CoursewareManagerLinkSelector.vue
index 1f4774f..a735024 100644
--- a/resources/vue/components/courseware/CoursewareManagerLinkSelector.vue
+++ b/resources/vue/components/courseware/CoursewareManagerLinkSelector.vue
@@ -13,15 +13,11 @@
<script>
import CoursewareManagerElement from './CoursewareManagerElement.vue';
-import CoursewareCompanionBox from './CoursewareCompanionBox.vue';
import { mapActions, mapGetters } from 'vuex';
export default {
name: 'courseware-manager-link-selector',
- components: {
- CoursewareManagerElement,
- CoursewareCompanionBox,
- },
+ components: { CoursewareManagerElement },
data() {
return {
@@ -75,4 +71,4 @@ export default {
await this.loadOwnCourseware();
},
}
-</script> \ No newline at end of file
+</script>
diff --git a/resources/vue/components/courseware/CoursewareStructuralElement.vue b/resources/vue/components/courseware/CoursewareStructuralElement.vue
index 25fff6f..e8de3b1 100644
--- a/resources/vue/components/courseware/CoursewareStructuralElement.vue
+++ b/resources/vue/components/courseware/CoursewareStructuralElement.vue
@@ -229,7 +229,7 @@
><studip-icon shape="arr_1down" size="10"
/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung</translate>.
</template>
<template #selected-option="{ name, hex }">
@@ -1278,13 +1278,15 @@ export default {
return containers;
},
+
owner() {
- const user = this.$store.getters['users/related']({
- parent: { type: this.structuralElement.type, id: this.structuralElement.id },
- relationship: 'owner'
+ const owner = this.relatedUsers({
+ parent: this.structuralElement,
+ relationship: 'owner',
});
- return user ?? null;
+ return owner ?? null;
},
+
ownerName() {
return this.owner?.attributes['formatted-name'] ?? '?';
},
@@ -1574,7 +1576,9 @@ export default {
async createElement() {
let title = this.newChapterName; // this is the title of the new element
let parent_id = this.currentId; // new page is descandant as default
- if (this.errorEmptyChapterName = title.trim() === '') {
+
+ this.errorEmptyChapterName = title.trim();
+ if (this.errorEmptyChapterName === '') {
return;
}
if (this.newChapterParent === 'sibling') {
diff --git a/resources/vue/components/courseware/CoursewareTabs.vue b/resources/vue/components/courseware/CoursewareTabs.vue
index 13a6b79..b5cc5a6 100644
--- a/resources/vue/components/courseware/CoursewareTabs.vue
+++ b/resources/vue/components/courseware/CoursewareTabs.vue
@@ -39,8 +39,8 @@ export default {
},
computed: {
sortedTabs() {
- return this.tabs.sort((a, b) => {
- return a.index > b.index ? 1 : a.index < b.index ? -1 : 0;
+ return [...this.tabs].sort((a, b) => {
+ return a.index - b.index;
});
}
},
@@ -106,7 +106,7 @@ export default {
},
getTabButtonByName(name) {
let selectorId = null;
- this.tabs.forEach((tab) => {
+ this.tabs.forEach((tab) => {
if (tab.name === name) {
selectorId = tab.selectorId;
}
@@ -118,7 +118,7 @@ export default {
},
getTabButtonByAlias(alias) {
let selectorId = null;
- this.tabs.forEach((tab) => {
+ this.tabs.forEach((tab) => {
if (tab.alias === alias) {
selectorId = tab.selectorId;
}
diff --git a/resources/vue/components/courseware/CoursewareTabsContainer.vue b/resources/vue/components/courseware/CoursewareTabsContainer.vue
index 15b3c87..b07d2a6 100644
--- a/resources/vue/components/courseware/CoursewareTabsContainer.vue
+++ b/resources/vue/components/courseware/CoursewareTabsContainer.vue
@@ -78,7 +78,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="option">
@@ -259,7 +259,7 @@ export default {
return null;
},
updateContent(blockAdder) {
- if(blockAdder.hasOwnProperty('container') && blockAdder.container.id === this.container.id) {
+ if(blockAdder.container !== undefined && blockAdder.container.id === this.container.id) {
this.initCurrentData();
}
}
diff --git a/resources/vue/components/courseware/CoursewareTimelineBlock.vue b/resources/vue/components/courseware/CoursewareTimelineBlock.vue
index 451478e..d8db917 100755
--- a/resources/vue/components/courseware/CoursewareTimelineBlock.vue
+++ b/resources/vue/components/courseware/CoursewareTimelineBlock.vue
@@ -11,7 +11,7 @@
>
<template #content>
<ol class="cw-timeline">
- <li
+ <li
v-for="(item, index) in sortedItems"
:key="index"
class="cw-timeline-item"
@@ -90,7 +90,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="{name, hex}">
@@ -107,7 +107,7 @@
<template #open-indicator="selectAttributes">
<span v-bind="selectAttributes"><studip-icon shape="arr_1down" size="10"/></span>
</template>
- <template #no-options="{ search, searching, loading }">
+ <template #no-options>
<translate>Es steht keine Auswahl zur Verfügung.</translate>
</template>
<template #selected-option="option">
diff --git a/resources/vue/components/courseware/CoursewareToolsAdmin.vue b/resources/vue/components/courseware/CoursewareToolsAdmin.vue
index 36dfee2..337a39e 100644
--- a/resources/vue/components/courseware/CoursewareToolsAdmin.vue
+++ b/resources/vue/components/courseware/CoursewareToolsAdmin.vue
@@ -57,7 +57,6 @@ export default {
permission: this.currentPermissionLevel,
progression: this.currentProgression,
});
-;
},
},
mounted() {