diff options
author | André Jaenisch <Ryuno-Ki@users.noreply.github.com> | 2022-10-01 16:26:38 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-01 22:26:38 +0800 |
commit | 04e97b83115e7439d43c0ede5fe2d1b50d201c52 (patch) | |
tree | 073a20e9377c5197112327afd11d7a6f2cccb268 /web_src | |
parent | 726afe8a9e33128476e1dc85f262fe56f995d12c (diff) | |
download | gitea-04e97b83115e7439d43c0ede5fe2d1b50d201c52.tar.gz gitea-04e97b83115e7439d43c0ede5fe2d1b50d201c52.zip |
Refactor from Vue2 to Vue3 (#20044)
Close #19902
Diffstat (limited to 'web_src')
-rw-r--r-- | web_src/js/components/ActivityHeatmap.vue | 2 | ||||
-rw-r--r-- | web_src/js/components/ContextPopup.vue | 12 | ||||
-rw-r--r-- | web_src/js/components/DashboardRepoList.js | 40 | ||||
-rw-r--r-- | web_src/js/components/DiffFileList.vue | 4 | ||||
-rw-r--r-- | web_src/js/components/DiffFileTree.vue | 8 | ||||
-rw-r--r-- | web_src/js/components/RepoBranchTagDropdown.js | 43 | ||||
-rw-r--r-- | web_src/js/components/VueComponentLoader.js | 20 | ||||
-rw-r--r-- | web_src/js/features/contextpopup.js | 13 | ||||
-rw-r--r-- | web_src/js/features/heatmap.js | 8 | ||||
-rw-r--r-- | web_src/js/features/repo-diff-filetree.js | 18 | ||||
-rw-r--r-- | web_src/js/features/repo-issue-pr-form.js | 8 | ||||
-rw-r--r-- | web_src/js/svg.js | 7 | ||||
-rw-r--r-- | web_src/less/features/heatmap.less | 8 |
13 files changed, 95 insertions, 96 deletions
diff --git a/web_src/js/components/ActivityHeatmap.vue b/web_src/js/components/ActivityHeatmap.vue index fa2c43b5b4..b5c5c65bbf 100644 --- a/web_src/js/components/ActivityHeatmap.vue +++ b/web_src/js/components/ActivityHeatmap.vue @@ -15,7 +15,7 @@ </div> </template> <script> -import {CalendarHeatmap} from 'vue-calendar-heatmap'; +import {CalendarHeatmap} from 'vue3-calendar-heatmap'; export default { name: 'ActivityHeatmap', diff --git a/web_src/js/components/ContextPopup.vue b/web_src/js/components/ContextPopup.vue index c176a18659..0b086690a9 100644 --- a/web_src/js/components/ContextPopup.vue +++ b/web_src/js/components/ContextPopup.vue @@ -1,5 +1,5 @@ <template> - <div> + <div ref="root"> <div v-if="loading" class="ui active centered inline loader"/> <div v-if="!loading && issue !== null"> <p><small>{{ issue.repository.full_name }} on {{ createdAt }}</small></p> @@ -109,15 +109,16 @@ export default { }, mounted() { - this.$root.$on('load-context-popup', (data, callback) => { + this.$refs.root.addEventListener('us-load-context-popup', (e) => { + const data = e.detail; if (!this.loading && this.issue === null) { - this.load(data, callback); + this.load(data); } }); }, methods: { - load(data, callback) { + load(data) { this.loading = true; this.i18nErrorMessage = null; $.get(`${appSubUrl}/${data.owner}/${data.repo}/issues/${data.index}/info`).done((issue) => { @@ -130,9 +131,6 @@ export default { } }).always(() => { this.loading = false; - if (callback) { - this.$nextTick(callback); - } }); } } diff --git a/web_src/js/components/DashboardRepoList.js b/web_src/js/components/DashboardRepoList.js index cbbc12c2c4..0a009e78d1 100644 --- a/web_src/js/components/DashboardRepoList.js +++ b/web_src/js/components/DashboardRepoList.js @@ -1,12 +1,12 @@ -import Vue from 'vue'; +import {createApp, nextTick} from 'vue'; import $ from 'jquery'; import {initVueSvg, vueDelimiters} from './VueComponentLoader.js'; import {initTooltip} from '../modules/tippy.js'; const {appSubUrl, assetUrlPrefix, pageData} = window.config; -function initVueComponents() { - Vue.component('repo-search', { +function initVueComponents(app) { + app.component('repo-search', { delimiters: vueDelimiters, props: { searchLimit: { @@ -138,13 +138,14 @@ function initVueComponents() { }, mounted() { + const el = document.getElementById('dashboard-repo-list'); this.changeReposFilter(this.reposFilter); - for (const el of this.$el.querySelectorAll('.tooltip')) { - initTooltip(el); + for (const elTooltip of el.querySelectorAll('.tooltip')) { + initTooltip(elTooltip); } - $(this.$el).find('.dropdown').dropdown(); + $(el).find('.dropdown').dropdown(); this.setCheckboxes(); - Vue.nextTick(() => { + nextTick(() => { this.$refs.search.focus(); }); }, @@ -192,7 +193,7 @@ function initVueComponents() { this.reposFilter = filter; this.repos = []; this.page = 1; - Vue.set(this.counts, `${filter}:${this.archivedFilter}:${this.privateFilter}`, 0); + this.counts[`${filter}:${this.archivedFilter}:${this.privateFilter}`] = 0; this.searchRepos(); }, @@ -261,7 +262,7 @@ function initVueComponents() { this.page = 1; this.repos = []; this.setCheckboxes(); - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0); + this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0; this.searchRepos(); }, @@ -283,7 +284,7 @@ function initVueComponents() { this.page = 1; this.repos = []; this.setCheckboxes(); - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0); + this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0; this.searchRepos(); }, @@ -297,7 +298,7 @@ function initVueComponents() { this.page = 1; } this.repos = []; - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0); + this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0; this.searchRepos(); }, @@ -331,7 +332,7 @@ function initVueComponents() { if (searchedQuery === '' && searchedMode === '' && this.archivedFilter === 'both') { this.reposTotalCount = count; } - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, count); + this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = count; this.finalPage = Math.ceil(count / this.searchLimit); this.updateHistory(); this.isLoading = false; @@ -352,22 +353,20 @@ function initVueComponents() { } return 'octicon-repo'; } - } + }, + + template: document.getElementById('dashboard-repo-list-template'), }); } - export function initDashboardRepoList() { const el = document.getElementById('dashboard-repo-list'); const dashboardRepoListData = pageData.dashboardRepoList || null; if (!el || !dashboardRepoListData) return; - initVueSvg(); - initVueComponents(); - new Vue({ - el, + const app = createApp({ delimiters: vueDelimiters, - data: () => { + data() { return { searchLimit: dashboardRepoListData.searchLimit || 0, subUrl: appSubUrl, @@ -375,4 +374,7 @@ export function initDashboardRepoList() { }; }, }); + initVueSvg(app); + initVueComponents(app); + app.mount(el); } diff --git a/web_src/js/components/DiffFileList.vue b/web_src/js/components/DiffFileList.vue index 2a9aa77377..da53be3b46 100644 --- a/web_src/js/components/DiffFileList.vue +++ b/web_src/js/components/DiffFileList.vue @@ -1,5 +1,5 @@ <template> - <ol class="diff-detail-box diff-stats m-0" id="diff-files" v-if="fileListIsVisible"> + <ol class="diff-detail-box diff-stats m-0" ref="root" v-if="fileListIsVisible"> <li v-for="file in files" :key="file.NameHash"> <div class="bold df ac pull-right"> <span v-if="file.IsBin" class="ml-1 mr-3">{{ binaryFileMessage }}</span> @@ -37,7 +37,7 @@ export default { fileListIsVisible(newValue) { if (newValue === true) { this.$nextTick(() => { - for (const el of this.$el.querySelectorAll('.tooltip')) { + for (const el of this.$refs.root.querySelectorAll('.tooltip')) { initTooltip(el); } }); diff --git a/web_src/js/components/DiffFileTree.vue b/web_src/js/components/DiffFileTree.vue index d0962254cd..717ba70f7f 100644 --- a/web_src/js/components/DiffFileTree.vue +++ b/web_src/js/components/DiffFileTree.vue @@ -1,11 +1,10 @@ <template> <div - v-show="fileTreeIsVisible" - id="diff-file-tree" + v-if="fileTreeIsVisible" class="mr-3 mt-3 diff-detail-box" > <!-- only render the tree if we're visible. in many cases this is something that doesn't change very often --> - <div class="ui list" v-if="fileTreeIsVisible"> + <div class="ui list"> <DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item" /> </div> <div v-if="isIncomplete" id="diff-too-many-files-stats" class="pt-2"> @@ -117,6 +116,9 @@ export default { const [toShow, toHide] = document.querySelectorAll('.diff-toggle-file-tree-button .icon'); toShow.classList.toggle('hide', visible); // hide the toShow icon if the tree is visible toHide.classList.toggle('hide', !visible); // similarly + + const diffTree = document.getElementById('diff-file-tree'); + diffTree.classList.toggle('hide', !visible); }, loadMoreData() { this.isLoadingNewData = true; diff --git a/web_src/js/components/RepoBranchTagDropdown.js b/web_src/js/components/RepoBranchTagDropdown.js index d55fa91b92..8bed305fca 100644 --- a/web_src/js/components/RepoBranchTagDropdown.js +++ b/web_src/js/components/RepoBranchTagDropdown.js @@ -1,4 +1,4 @@ -import Vue from 'vue'; +import {createApp, nextTick} from 'vue'; import $ from 'jquery'; import {vueDelimiters} from './VueComponentLoader.js'; @@ -37,10 +37,14 @@ export function initRepoBranchTagDropdown(selector) { }); }); $data.remove(); - new Vue({ - el: this, + + // eslint-disable-next-line unicorn/no-this-assignment + const elRoot = this; + const view = createApp({ delimiters: vueDelimiters, - data, + data() { + return data; + }, computed: { filteredItems() { const items = this.items.filter((item) => { @@ -73,10 +77,10 @@ export function initRepoBranchTagDropdown(selector) { }, beforeMount() { - this.noResults = this.$el.getAttribute('data-no-results'); - this.canCreateBranch = this.$el.getAttribute('data-can-create-branch') === 'true'; - this.branchForm = this.$el.getAttribute('data-branch-form'); - switch (this.$el.getAttribute('data-view-type')) { + this.noResults = elRoot.getAttribute('data-no-results'); + this.canCreateBranch = elRoot.getAttribute('data-can-create-branch') === 'true'; + this.branchForm = elRoot.getAttribute('data-branch-form'); + switch (elRoot.getAttribute('data-view-type')) { case 'tree': this.isViewTree = true; break; @@ -87,19 +91,19 @@ export function initRepoBranchTagDropdown(selector) { this.isViewBranch = true; break; } - this.refName = this.$el.getAttribute('data-ref-name'); - this.branchURLPrefix = this.$el.getAttribute('data-branch-url-prefix'); - this.branchURLSuffix = this.$el.getAttribute('data-branch-url-suffix'); - this.tagURLPrefix = this.$el.getAttribute('data-tag-url-prefix'); - this.tagURLSuffix = this.$el.getAttribute('data-tag-url-suffix'); - this.setAction = this.$el.getAttribute('data-set-action') === 'true'; - this.submitForm = this.$el.getAttribute('data-submit-form') === 'true'; + this.refName = elRoot.getAttribute('data-ref-name'); + this.branchURLPrefix = elRoot.getAttribute('data-branch-url-prefix'); + this.branchURLSuffix = elRoot.getAttribute('data-branch-url-suffix'); + this.tagURLPrefix = elRoot.getAttribute('data-tag-url-prefix'); + this.tagURLSuffix = elRoot.getAttribute('data-tag-url-suffix'); + this.setAction = elRoot.getAttribute('data-set-action') === 'true'; + this.submitForm = elRoot.getAttribute('data-submit-form') === 'true'; document.body.addEventListener('click', (event) => { - if (this.$el.contains(event.target)) return; + if (elRoot.contains(event.target)) return; if (this.menuVisible) { - Vue.set(this, 'menuVisible', false); + this.menuVisible = false; } }); }, @@ -135,7 +139,7 @@ export function initRepoBranchTagDropdown(selector) { if (this.submitForm) { $(`#${this.branchForm}`).trigger('submit'); } - Vue.set(this, 'menuVisible', false); + this.menuVisible = false; } }, createNewBranch() { @@ -143,7 +147,7 @@ export function initRepoBranchTagDropdown(selector) { $(this.$refs.newBranchForm).trigger('submit'); }, focusSearchField() { - Vue.nextTick(() => { + nextTick(() => { this.$refs.searchField.focus(); }); }, @@ -213,5 +217,6 @@ export function initRepoBranchTagDropdown(selector) { } } }); + view.mount(this); }); } diff --git a/web_src/js/components/VueComponentLoader.js b/web_src/js/components/VueComponentLoader.js index 2979cd6a86..f0555b21cc 100644 --- a/web_src/js/components/VueComponentLoader.js +++ b/web_src/js/components/VueComponentLoader.js @@ -1,4 +1,4 @@ -import Vue from 'vue'; +import {createApp} from 'vue'; import {svgs} from '../svg.js'; export const vueDelimiters = ['${', '}']; @@ -8,13 +8,14 @@ export function initVueEnv() { if (vueEnvInited) return; vueEnvInited = true; - const isProd = window.config.runModeIsProd; - Vue.config.productionTip = false; - Vue.config.devtools = !isProd; + // As far as I could tell, this is no longer possible. + // But there seem not to be a guide what to do instead. + // const isProd = window.config.runModeIsProd; + // Vue.config.devtools = !isProd; } let vueSvgInited = false; -export function initVueSvg() { +export function initVueSvg(app) { if (vueSvgInited) return; vueSvgInited = true; @@ -24,7 +25,7 @@ export function initVueSvg() { .replace(/height="[0-9]+"/, 'v-bind:height="size"') .replace(/width="[0-9]+"/, 'v-bind:width="size"'); - Vue.component(name, { + app.component(name, { props: { size: { type: String, @@ -42,8 +43,7 @@ export function initVueApp(el, opts = {}) { } if (!el) return null; - return new Vue(Object.assign({ - el, - delimiters: vueDelimiters, - }, opts)); + return createApp( + Object.assign({delimiters: vueDelimiters}, opts) + ).mount(el); } diff --git a/web_src/js/features/contextpopup.js b/web_src/js/features/contextpopup.js index f4e660be3f..d29da6d951 100644 --- a/web_src/js/features/contextpopup.js +++ b/web_src/js/features/contextpopup.js @@ -1,5 +1,5 @@ import $ from 'jquery'; -import Vue from 'vue'; +import {createApp} from 'vue'; import ContextPopup from '../components/ContextPopup.vue'; import {parseIssueHref} from '../utils.js'; import {createTippy} from '../modules/tippy.js'; @@ -17,17 +17,12 @@ export default function initContextPopups() { if (!owner) return; const el = document.createElement('div'); - el.innerHTML = '<div></div>'; this.parentNode.insertBefore(el, this.nextSibling); - const View = Vue.extend({ - render: (createElement) => createElement(ContextPopup), - }); - - const view = new View(); + const view = createApp(ContextPopup); try { - view.$mount(el.firstChild); + view.mount(el); } catch (err) { console.error(err); el.textContent = 'ContextPopup failed to load'; @@ -37,7 +32,7 @@ export default function initContextPopups() { content: el, interactive: true, onShow: () => { - view.$emit('load-context-popup', {owner, repo, index}); + el.firstChild.dispatchEvent(new CustomEvent('us-load-context-popup', {detail: {owner, repo, index}})); } }); }); diff --git a/web_src/js/features/heatmap.js b/web_src/js/features/heatmap.js index 363be5ca75..6e6202e866 100644 --- a/web_src/js/features/heatmap.js +++ b/web_src/js/features/heatmap.js @@ -1,4 +1,4 @@ -import Vue from 'vue'; +import {createApp} from 'vue'; import ActivityHeatmap from '../components/ActivityHeatmap.vue'; export default function initHeatmap() { @@ -17,11 +17,9 @@ export default function initHeatmap() { return {date: new Date(v), count: heatmap[v]}; }); - const View = Vue.extend({ - render: (createElement) => createElement(ActivityHeatmap, {props: {values}}), - }); + const View = createApp(ActivityHeatmap, {values}); - new View().$mount(el); + View.mount(el); } catch (err) { console.error('Heatmap failed to load', err); el.textContent = 'Heatmap failed to load'; diff --git a/web_src/js/features/repo-diff-filetree.js b/web_src/js/features/repo-diff-filetree.js index 9eba3cf887..6059dd82e7 100644 --- a/web_src/js/features/repo-diff-filetree.js +++ b/web_src/js/features/repo-diff-filetree.js @@ -1,21 +1,17 @@ -import Vue from 'vue'; +import {createApp} from 'vue'; import DiffFileTree from '../components/DiffFileTree.vue'; import DiffFileList from '../components/DiffFileList.vue'; export default function initDiffFileTree() { - const el = document.getElementById('diff-file-tree-container'); + const el = document.getElementById('diff-file-tree'); if (!el) return; - const View = Vue.extend({ - render: (createElement) => createElement(DiffFileTree), - }); - new View().$mount(el); + const fileTreeView = createApp(DiffFileTree); + fileTreeView.mount(el); - const fileListElement = document.getElementById('diff-file-list-container'); + const fileListElement = document.getElementById('diff-file-list'); if (!fileListElement) return; - const fileListView = Vue.extend({ - render: (createElement) => createElement(DiffFileList), - }); - new fileListView().$mount(fileListElement); + const fileListView = createApp(DiffFileList); + fileListView.mount(fileListElement); } diff --git a/web_src/js/features/repo-issue-pr-form.js b/web_src/js/features/repo-issue-pr-form.js index 747e4f467e..59d4c7a3b4 100644 --- a/web_src/js/features/repo-issue-pr-form.js +++ b/web_src/js/features/repo-issue-pr-form.js @@ -1,12 +1,10 @@ -import Vue from 'vue'; +import {createApp} from 'vue'; import PullRequestMergeForm from '../components/PullRequestMergeForm.vue'; export default function initPullRequestMergeForm() { const el = document.getElementById('pull-request-merge-form'); if (!el) return; - const View = Vue.extend({ - render: (createElement) => createElement(PullRequestMergeForm), - }); - new View().$mount(el); + const view = createApp(PullRequestMergeForm); + view.mount(el); } diff --git a/web_src/js/svg.js b/web_src/js/svg.js index 6677bf83cb..dedc126303 100644 --- a/web_src/js/svg.js +++ b/web_src/js/svg.js @@ -26,8 +26,6 @@ import octiconSidebarExpand from '../../public/img/svg/octicon-sidebar-expand.sv import octiconSidebarCollapse from '../../public/img/svg/octicon-sidebar-collapse.svg'; -import Vue from 'vue'; - export const svgs = { 'octicon-chevron-down': octiconChevronDown, 'octicon-chevron-right': octiconChevronRight, @@ -74,7 +72,8 @@ export function svg(name, size = 16, className = '') { return serializer.serializeToString(svgNode); } -export const SvgIcon = Vue.component('SvgIcon', { +export const SvgIcon = { + name: 'SvgIcon', props: { name: {type: String, required: true}, size: {type: Number, default: 16}, @@ -88,4 +87,4 @@ export const SvgIcon = Vue.component('SvgIcon', { }, template: `<span v-html="svg" />` -}); +}; diff --git a/web_src/less/features/heatmap.less b/web_src/less/features/heatmap.less index f551daf333..952d6f35ed 100644 --- a/web_src/less/features/heatmap.less +++ b/web_src/less/features/heatmap.less @@ -3,10 +3,16 @@ text-align: center; position: relative; min-height: 125px; - display: flex; align-items: center; justify-content: center; + // for the "Less" and "More" legend + .vch__legend .vch__legend div:first-child, + .vch__legend .vch__legend div:last-child { + display: inline-block; + padding: 0 5px; + } + > svg { width: 100%; } |