diff options
| author | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2024-12-04 15:24:25 +0000 |
|---|---|---|
| committer | Jan-Hendrik Willms <tleilax+studip@gmail.com> | 2024-12-04 15:24:25 +0000 |
| commit | fac89b11bc20d86ec435c1b450ccc50219002ecf (patch) | |
| tree | 6d779253179cd5813aa5ab315d4a0d106fbbfe4c /resources/assets/javascripts/bootstrap | |
| parent | d448125b9902919c070ce7aecbfdfe1b47feb3b5 (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.js | 6 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/courseware.js | 36 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/forms.js | 43 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/mvv_difflog.js | 18 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/oer.js | 21 | ||||
| -rw-r--r-- | resources/assets/javascripts/bootstrap/vue.js | 170 |
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); }); }); |
