aboutsummaryrefslogtreecommitdiff
path: root/resources/assets/javascripts/bootstrap
diff options
context:
space:
mode:
authorJan-Hendrik Willms <tleilax+studip@gmail.com>2024-12-04 15:24:25 +0000
committerJan-Hendrik Willms <tleilax+studip@gmail.com>2024-12-04 15:24:25 +0000
commitfac89b11bc20d86ec435c1b450ccc50219002ecf (patch)
tree6d779253179cd5813aa5ab315d4a0d106fbbfe4c /resources/assets/javascripts/bootstrap
parentd448125b9902919c070ce7aecbfdfe1b47feb3b5 (diff)
update vue2 -> vue3, fixes #3747
Closes #3747 Merge request studip/studip!3108
Diffstat (limited to 'resources/assets/javascripts/bootstrap')
-rw-r--r--resources/assets/javascripts/bootstrap/avatar.js6
-rw-r--r--resources/assets/javascripts/bootstrap/courseware.js36
-rw-r--r--resources/assets/javascripts/bootstrap/forms.js43
-rw-r--r--resources/assets/javascripts/bootstrap/mvv_difflog.js18
-rw-r--r--resources/assets/javascripts/bootstrap/oer.js21
-rw-r--r--resources/assets/javascripts/bootstrap/vue.js170
6 files changed, 152 insertions, 142 deletions
diff --git a/resources/assets/javascripts/bootstrap/avatar.js b/resources/assets/javascripts/bootstrap/avatar.js
index 31d724d..9c1de1c 100644
--- a/resources/assets/javascripts/bootstrap/avatar.js
+++ b/resources/assets/javascripts/bootstrap/avatar.js
@@ -4,13 +4,13 @@ STUDIP.domReady(() => {
avatarTypes.forEach((type) => {
if (document.getElementById(`avatar-${type}-app`)) {
Promise.all([
- STUDIP.loadChunk('avatar'),
+ STUDIP.loadChunk('vue'),
import(
/* webpackChunkName: "avatar-app" */
'@/vue/avatar-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, `#avatar-${type}-app`);
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, `#avatar-${type}-app`);
});
}
});
diff --git a/resources/assets/javascripts/bootstrap/courseware.js b/resources/assets/javascripts/bootstrap/courseware.js
index b90cc45..72503e0 100644
--- a/resources/assets/javascripts/bootstrap/courseware.js
+++ b/resources/assets/javascripts/bootstrap/courseware.js
@@ -6,8 +6,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-shelf-app" */
'@/vue/courseware-shelf-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-shelf-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-shelf-app');
});
}
@@ -18,8 +18,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-index-app" */
'@/vue/courseware-index-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-index-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-index-app');
});
}
@@ -30,8 +30,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-activities-app" */
'@/vue/courseware-activities-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-activities-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-activities-app');
});
}
@@ -42,8 +42,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-tasks-app" */
'@/vue/courseware-tasks-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-tasks-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-tasks-app');
});
}
@@ -54,8 +54,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-content-bookmark-app" */
'@/vue/courseware-content-bookmark-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-content-bookmark-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-content-bookmark-app');
});
}
@@ -66,8 +66,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-content-bookmark-app" */
'@/vue/courseware-admin-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-admin-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-admin-app');
});
}
@@ -78,8 +78,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-public-app" */
'@/vue/courseware-public-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-public-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-public-app');
});
}
@@ -90,8 +90,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-content-releases-app" */
'@/vue/courseware-content-releases-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-content-releases-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-content-releases-app');
});
}
@@ -102,8 +102,8 @@ STUDIP.domReady(() => {
/* webpackChunkName: "courseware-comments-app" */
'@/vue/courseware-comments-app.js'
),
- ]).then(([{ createApp }, { default: mountApp }]) => {
- return mountApp(STUDIP, createApp, '#courseware-comments-app');
+ ]).then(([{ createApp, store }, { default: mountApp }]) => {
+ return mountApp(STUDIP, createApp, store, '#courseware-comments-app');
});
}
diff --git a/resources/assets/javascripts/bootstrap/forms.js b/resources/assets/javascripts/bootstrap/forms.js
index e159699..bd863eb 100644
--- a/resources/assets/javascripts/bootstrap/forms.js
+++ b/resources/assets/javascripts/bootstrap/forms.js
@@ -1,5 +1,6 @@
-import { $gettext, $gettextInterpolate } from '../lib/gettext';
+import { $gettext } from '../lib/gettext';
import Report from '../lib/report.ts';
+import Dialog from "../lib/dialog";
// Allow fieldsets to collapse
$(document).on(
@@ -242,12 +243,13 @@ function createSelect2(element) {
}
STUDIP.ready(function () {
- let forms = window.document.querySelectorAll('form.default.studipform:not(.vueified)');
+ let forms = window.document.querySelectorAll('.studipform:not(.vueified)');
if (forms.length > 0) {
STUDIP.Vue.load().then(({createApp}) => {
forms.forEach(f => {
- createApp({
- el: f,
+ f.classList.add('vueified');
+
+ const app = createApp({
data() {
let params = JSON.parse(f.dataset.inputs);
params.STUDIPFORM_REQUIRED = f.dataset.required ? JSON.parse(f.dataset.required) : [];
@@ -343,9 +345,9 @@ STUDIP.ready(function () {
note.description = $(this).data('validation_requirement');
}
if (this.validity.tooShort) {
- note.description = $gettextInterpolate(
- $gettext('Geben Sie mindestens %{min} Zeichen ein.'),
- {min: this.minLength}
+ note.description = $gettext(
+ 'Geben Sie mindestens %{min} Zeichen ein.',
+ { min: this.minLength }
);
}
if (this.validity.valueMissing) {
@@ -353,9 +355,9 @@ STUDIP.ready(function () {
note.description = $gettext('Dieses Feld muss ausgewählt sein.');
} else {
if (this.minLength > 0) {
- note.description = $gettextInterpolate(
- $gettext('Hier muss ein Wert mit mindestens %{min} Zeichen eingetragen werden.'),
- {min: this.minLength}
+ note.description = $gettext(
+ 'Hier muss ein Wert mit mindestens %{min} Zeichen eingetragen werden.',
+ { min: this.minLength }
);
} else {
note.description = $gettext('Hier muss ein Wert eingetragen werden.');
@@ -419,10 +421,19 @@ STUDIP.ready(function () {
return orderedNotes;
}
},
- mounted () {
- $(this.$el).addClass("vueified");
+ mounted() {
+ if (this.$el.closest('.ui-dialog')) {
+ const cancelButton = this.$el.querySelector('footer .button.cancel:last-of-type');
+ if (cancelButton) {
+ cancelButton.addEventListener('click', (e) => {
+ Dialog.close();
+ e.preventDefault();
+ })
+ }
+ }
}
});
+ app.mount(f);
});
});
}
@@ -435,12 +446,8 @@ STUDIP.ready(function () {
if (simple_vue_items.length > 0) {
STUDIP.Vue.load().then(({createApp}) => {
simple_vue_items.forEach(f => {
- createApp({
- el: f,
- mounted() {
- this.$el.classList.add('vueified');
- }
- });
+ f.classList.add('vueified');
+ createApp().mount(f);
});
});
}
diff --git a/resources/assets/javascripts/bootstrap/mvv_difflog.js b/resources/assets/javascripts/bootstrap/mvv_difflog.js
index 8ade918..0d970ec 100644
--- a/resources/assets/javascripts/bootstrap/mvv_difflog.js
+++ b/resources/assets/javascripts/bootstrap/mvv_difflog.js
@@ -1,4 +1,4 @@
-import { $gettext, $gettextInterpolate } from '../lib/gettext';
+import { $gettext } from '../lib/gettext';
STUDIP.domReady(() => {
$('del.diffdel').each(function() {
@@ -44,8 +44,8 @@ STUDIP.domReady(() => {
senddata,
function(data) {
if (data) {
- var info = $gettextInterpolate(
- $gettext('Entfernt von %{user} am %{time}'),
+ var info = $gettext(
+ 'Entfernt von %{user} am %{time}',
data
);
del.attr('title', info);
@@ -140,8 +140,8 @@ STUDIP.domReady(() => {
senddata,
function(data) {
if (data) {
- var info = $gettextInterpolate(
- $gettext('Änderung durch %{user} am %{time}'),
+ var info = $gettext(
+ 'Änderung durch %{user} am %{time}',
data
);
ins.attr('title', info);
@@ -175,8 +175,8 @@ STUDIP.domReady(() => {
);
function onSuccess(data) {
if (data) {
- var info = $gettextInterpolate(
- $gettext('Hinzugefügt von %{user} am %{time}'),
+ var info = $gettext(
+ 'Hinzugefügt von %{user} am %{time}',
data
);
curtable.attr('title', info);
@@ -210,8 +210,8 @@ STUDIP.domReady(() => {
);
function onSuccess(data) {
if (data) {
- var info = $gettextInterpolate(
- $gettext('Entfernt von %{user} am %{time}'),
+ var info = $gettext(
+ 'Entfernt von %{user} am %{time}',
data
);
curtable.attr('title', info);
diff --git a/resources/assets/javascripts/bootstrap/oer.js b/resources/assets/javascripts/bootstrap/oer.js
index 2b47149..0854e8b 100644
--- a/resources/assets/javascripts/bootstrap/oer.js
+++ b/resources/assets/javascripts/bootstrap/oer.js
@@ -1,5 +1,3 @@
-import Quicksearch from '../../../vue/components/Quicksearch.vue';
-
STUDIP.domReady(() => {
if (jQuery(".oer_search").length) {
STUDIP.OER.initSearch();
@@ -55,16 +53,15 @@ STUDIP.ready(() => {
if ($('.oercampus_editmaterial').length) {
STUDIP.Vue.load().then(({createApp}) => {
- STUDIP.OER.EditApp = createApp({
- el: '.oercampus_editmaterial',
+ const app = createApp({
data() {
return {
name: $('.oercampus_editmaterial input.oername').val(),
- logo_url: $('.oercampus_editmaterial .logo_file').data("oldurl"),
- customlogo: $('.oercampus_editmaterial .logo_file').data("customlogo"),
+ logo_url: $('.oercampus_editmaterial .logo_file').data("oldurl") ?? null,
+ customlogo: $('.oercampus_editmaterial .logo_file').data("customlogo") == '1',
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"),
+ tags: $('.oercampus_editmaterial .oer_tags').data("defaulttags") ?? [],
minimumTags: 5
};
},
@@ -87,10 +84,9 @@ STUDIP.ready(() => {
},
editImage: function (event) {
let reader = new FileReader();
- let vue = this;
- reader.addEventListener("load", function () {
- vue.logo_url = reader.result;
- vue.customlogo = true;
+ reader.addEventListener("load", () => {
+ this.logo_url = reader.result;
+ this.customlogo = true;
}, false);
reader.readAsDataURL(
event.target.files.length > 0
@@ -137,8 +133,9 @@ STUDIP.ready(() => {
return result;
}
},
- components: { Quicksearch }
});
+ app.mount('.oercampus_editmaterial');
+ STUDIP.OER.EditApp = app;
});
}
});
diff --git a/resources/assets/javascripts/bootstrap/vue.js b/resources/assets/javascripts/bootstrap/vue.js
index 513c796..4b1ac6d 100644
--- a/resources/assets/javascripts/bootstrap/vue.js
+++ b/resources/assets/javascripts/bootstrap/vue.js
@@ -1,5 +1,37 @@
+import { defineAsyncComponent } from 'vue';
+
+function attachComponents(app, configuredComponents) {
+ configuredComponents.forEach(component => {
+ const name = component.split('/').reverse()[0];
+ app.component(name, defineAsyncComponent(() => {
+ const temp = import(`../../../vue/components/${component}.vue`);
+ temp.then(({default: c}) => {
+ const mounted = c.mounted ?? null;
+ c.mounted = function (...args) {
+ if (
+ this.$el instanceof Element
+ && this.$el.closest('.studip-dialog')
+ && this.$el.querySelector('[data-dialog-button]')
+ ) {
+ this.$el.closest('.studip-dialog')
+ .querySelector('.ui-dialog-buttonpane')
+ .remove();
+ }
+ if (mounted) {
+ mounted.call(this, args);
+ }
+ };
+ return c;
+ })
+ return temp;
+ }));
+ });
+}
+
STUDIP.ready(() => {
- document.querySelectorAll('[data-vue-app]:not([data-vue-app-created])').forEach((node) => {
+ document.querySelectorAll('[data-vue-app]:not([data-vue-app-created])').forEach(async (node) => {
+ node.dataset.vueAppCreated = 'true';
+
const config = Object.assign(
{
components: [],
@@ -9,96 +41,70 @@ STUDIP.ready(() => {
JSON.parse(node.dataset.vueApp)
);
- let components = {};
- config.components.forEach(component => {
- const name = component.split('/').reverse()[0];
- components[name] = () => {
- // TODO: I wonder if this works with Vue3
+ const { createApp, store } = await STUDIP.Vue.load();
- const temp = import(`../../../vue/components/${component}.vue`);
- temp.then(({default: c}) => {
- const mounted = c.mounted ?? null;
- c.mounted = function (...args) {
- if (
- this.$el instanceof Element
- && this.$el.closest('.studip-dialog')
- && this.$el.querySelector('[data-dialog-button]')
- ) {
- this.$el.closest('.studip-dialog')
- .querySelector('.ui-dialog-buttonpane')
- .remove();
- }
- if (mounted) {
- mounted.call(this, args);
- }
- };
- return c;
- })
- return temp;
- };
- });
+ const promises = [Promise.resolve()];
- STUDIP.Vue.load().then(({createApp, store, Vue}) => {
- const promises = [Promise.resolve()];
+ for (const [index, name] of Object.entries(config.stores)) {
+ promises.push(
+ import(`../../../vue/store/${name}.js`).then(storeConfig => {
+ store.registerModule(index, storeConfig.default);
- for (const [index, name] of Object.entries(config.stores)) {
- promises.push(
- import(`../../../vue/store/${name}.js`).then(storeConfig => {
- store.registerModule(index, storeConfig.default);
+ const dataElement = document.getElementById(`vue-store-data-${index}`);
+ if (dataElement) {
+ const data = JSON.parse(dataElement.innerText);
+ Object.keys(data).forEach(command => {
+ store.commit(`${index}/${command}`, data[command]);
+ });
- const dataElement = document.getElementById(`vue-store-data-${index}`);
- if (dataElement) {
- const data = JSON.parse(dataElement.innerText);
- Object.keys(data).forEach(command => {
- store.commit(`${index}/${command}`, data[command]);
- });
+ dataElement.remove();
+ }
+ })
+ );
+ }
- dataElement.remove();
- }
- })
- );
- }
+ const plugins = [];
+ for (const [plugin, filename] of Object.entries(config.plugins)) {
+ promises.push(
+ import(`../../../vue/plugins/${filename}.js`)
+ .then((temp) => plugins.push(temp[plugin]))
+ );
+ }
- for (const [plugin, filename] of Object.entries(config.plugins)) {
- promises.push(
- import(`../../../vue/plugins/${filename}.js`)
- .then((temp) => Vue.use(temp[plugin], { store }))
- );
- }
+ await Promise.all(promises);
- Promise.all(promises).then(() => {
- createApp({
- components,
- store,
+ const app = createApp({
+ store,
- beforeCreate() {
- STUDIP.Vue.emit('VueAppWillCreate', this);
- },
- created() {
- STUDIP.Vue.emit('VueAppDidCreate', this);
- },
- beforeMount() {
- STUDIP.Vue.emit('VueAppWillMount', this);
- },
- mounted() {
- STUDIP.Vue.emit('VueAppDidMount', this);
- },
- beforeUpdate() {
- STUDIP.Vue.emit('VueAppWillUpdate', this);
- },
- updated() {
- STUDIP.Vue.emit('VueAppDidUpdate', this);
- },
- beforeDestroy() {
- STUDIP.Vue.emit('VueAppWillDestroy', this);
- },
- destroyed() {
- STUDIP.Vue.emit('VueAppDidDestroy', this);
- },
- }).$mount(node);
- });
+ beforeCreate() {
+ STUDIP.Vue.emit('VueAppWillCreate', this);
+ },
+ created() {
+ STUDIP.Vue.emit('VueAppDidCreate', this);
+ },
+ beforeMount() {
+ STUDIP.Vue.emit('VueAppWillMount', this);
+ },
+ mounted() {
+ STUDIP.Vue.emit('VueAppDidMount', this);
+ },
+ beforeUpdate() {
+ STUDIP.Vue.emit('VueAppWillUpdate', this);
+ },
+ updated() {
+ STUDIP.Vue.emit('VueAppDidUpdate', this);
+ },
+ beforeUnmount() {
+ STUDIP.Vue.emit('VueAppWillUnmount', this);
+ },
+ unmounted() {
+ STUDIP.Vue.emit('VueAppDidUnmount', this);
+ },
});
- node.dataset.vueAppCreated = 'true';
+ attachComponents(app, config.components);
+ plugins.forEach(plugin => app.use(plugin, { store }))
+
+ app.mount(node);
});
});