diff options
author | wxiaoguang <wxiaoguang@gmail.com> | 2021-10-15 10:35:26 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-10-15 10:35:26 +0800 |
commit | 56362043d35d2542c6fe4ac7c0ac5aabb833a9ed (patch) | |
tree | d3dd12505e7dd1b2d854c61384e1088f6901bab6 /web_src/js/index.js | |
parent | 96ff3e310f0ba1e94f4e8206758b583719a9b46c (diff) | |
download | gitea-56362043d35d2542c6fe4ac7c0ac5aabb833a9ed.tar.gz gitea-56362043d35d2542c6fe4ac7c0ac5aabb833a9ed.zip |
Frontend refactor: move Vue related code from `index.js` to `components` dir, and remove unused codes. (#17301)
* frontend refactor
* Apply suggestions from code review
Co-authored-by: delvh <dev.lh@web.de>
* Update templates/base/head.tmpl
Co-authored-by: delvh <dev.lh@web.de>
* Update docs/content/doc/developers/guidelines-frontend.md
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
* fix typo
* fix typo
* refactor PageData to pageData
* Apply suggestions from code review
Co-authored-by: delvh <dev.lh@web.de>
* Simply for the visual difference.
Co-authored-by: delvh <dev.lh@web.de>
* Revert "Apply suggestions from code review"
This reverts commit 4d78ad9b0e96ca180e0823de17659a2e0814c099.
Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: 6543 <6543@obermui.de>
Diffstat (limited to 'web_src/js/index.js')
-rw-r--r-- | web_src/js/index.js | 567 |
1 files changed, 11 insertions, 556 deletions
diff --git a/web_src/js/index.js b/web_src/js/index.js index bc9725da95..e6269c8abf 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -1,10 +1,13 @@ import './publicpath.js'; -import Vue from 'vue'; import {htmlEscape} from 'escape-goat'; import 'jquery.are-you-sure'; -import ActivityTopAuthors from './components/ActivityTopAuthors.vue'; +import {initVueEnv} from './components/VueComponentLoader.js'; +import {initRepoActivityTopAuthorsChart} from './components/RepoActivityTopAuthors.vue'; +import {initDashboardRepoList} from './components/DashboardRepoList.js'; +import {initRepoBranchTagDropdown} from './components/RepoBranchTagDropdown.js'; + import attachTribute from './features/tribute.js'; import createColorPicker from './features/colorpicker.js'; import createDropzone from './features/dropzone.js'; @@ -27,20 +30,16 @@ import {initStopwatch} from './features/stopwatch.js'; import {showLineButton} from './code/linebutton.js'; import {initMarkupContent, initCommentContent} from './markup/content.js'; import {stripTags, mqBinarySearch} from './utils.js'; -import {svg, svgs} from './svg.js'; +import {svg} from './svg.js'; -const {AppSubUrl, AssetUrlPrefix, csrf} = window.config; +const {AppSubUrl, csrf} = window.config; let previewFileModes; const commentMDEditors = {}; // Silence fomantic's error logging when tabs are used without a target content element $.fn.tab.settings.silent = true; - -// Silence Vue's console advertisements in dev mode -// To use the Vue browser extension, enable the devtools option temporarily -Vue.config.productionTip = false; -Vue.config.devtools = false; +initVueEnv(); function initCommentPreviewTab($form) { const $tabMenu = $form.find('.tabular.menu'); @@ -806,7 +805,7 @@ async function initRepository() { // File list and commits if ($('.repository.file.list').length > 0 || $('.repository.commits').length > 0 || $('.repository.release').length > 0) { - initFilterBranchTagDropdown('.choose.reference .dropdown'); + initRepoBranchTagDropdown('.choose.reference .dropdown'); } // Wiki @@ -2858,7 +2857,8 @@ $(document).ready(async () => { initWebhook(); initAdmin(); initCodeView(); - initVueApp(); + initRepoActivityTopAuthorsChart(); + initDashboardRepoList(); initTeamSettings(); initCtrlEnterSubmit(); initNavbarContentToggle(); @@ -3105,369 +3105,6 @@ function linkEmailAction(e) { e.preventDefault(); } -function initVueComponents() { - // register svg icon vue components, e.g. <octicon-repo size="16"/> - for (const [name, htmlString] of Object.entries(svgs)) { - const template = htmlString - .replace(/height="[0-9]+"/, 'v-bind:height="size"') - .replace(/width="[0-9]+"/, 'v-bind:width="size"'); - - Vue.component(name, { - props: { - size: { - type: String, - default: '16', - }, - }, - template, - }); - } - - const vueDelimeters = ['${', '}']; - - Vue.component('repo-search', { - delimiters: vueDelimeters, - - props: { - searchLimit: { - type: Number, - default: 10 - }, - suburl: { - type: String, - required: true - }, - uid: { - type: Number, - required: true - }, - teamId: { - type: Number, - required: false, - default: 0 - }, - organizations: { - type: Array, - default: () => [], - }, - isOrganization: { - type: Boolean, - default: true - }, - canCreateOrganization: { - type: Boolean, - default: false - }, - organizationsTotalCount: { - type: Number, - default: 0 - }, - moreReposLink: { - type: String, - default: '' - } - }, - - data() { - const params = new URLSearchParams(window.location.search); - - let tab = params.get('repo-search-tab'); - if (!tab) { - tab = 'repos'; - } - - let reposFilter = params.get('repo-search-filter'); - if (!reposFilter) { - reposFilter = 'all'; - } - - let privateFilter = params.get('repo-search-private'); - if (!privateFilter) { - privateFilter = 'both'; - } - - let archivedFilter = params.get('repo-search-archived'); - if (!archivedFilter) { - archivedFilter = 'unarchived'; - } - - let searchQuery = params.get('repo-search-query'); - if (!searchQuery) { - searchQuery = ''; - } - - let page = 1; - try { - page = parseInt(params.get('repo-search-page')); - } catch { - // noop - } - if (!page) { - page = 1; - } - - return { - tab, - repos: [], - reposTotalCount: 0, - reposFilter, - archivedFilter, - privateFilter, - page, - finalPage: 1, - searchQuery, - isLoading: false, - staticPrefix: AssetUrlPrefix, - counts: {}, - repoTypes: { - all: { - searchMode: '', - }, - forks: { - searchMode: 'fork', - }, - mirrors: { - searchMode: 'mirror', - }, - sources: { - searchMode: 'source', - }, - collaborative: { - searchMode: 'collaborative', - }, - } - }; - }, - - computed: { - showMoreReposLink() { - return this.repos.length > 0 && this.repos.length < this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`]; - }, - searchURL() { - return `${this.suburl}/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&team_id=${this.teamId}&q=${this.searchQuery - }&page=${this.page}&limit=${this.searchLimit}&mode=${this.repoTypes[this.reposFilter].searchMode - }${this.reposFilter !== 'all' ? '&exclusive=1' : '' - }${this.archivedFilter === 'archived' ? '&archived=true' : ''}${this.archivedFilter === 'unarchived' ? '&archived=false' : '' - }${this.privateFilter === 'private' ? '&is_private=true' : ''}${this.privateFilter === 'public' ? '&is_private=false' : '' - }`; - }, - repoTypeCount() { - return this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`]; - } - }, - - mounted() { - this.changeReposFilter(this.reposFilter); - $(this.$el).find('.poping.up').popup(); - $(this.$el).find('.dropdown').dropdown(); - this.setCheckboxes(); - Vue.nextTick(() => { - this.$refs.search.focus(); - }); - }, - - methods: { - changeTab(t) { - this.tab = t; - this.updateHistory(); - }, - - setCheckboxes() { - switch (this.archivedFilter) { - case 'unarchived': - $('#archivedFilterCheckbox').checkbox('set unchecked'); - break; - case 'archived': - $('#archivedFilterCheckbox').checkbox('set checked'); - break; - case 'both': - $('#archivedFilterCheckbox').checkbox('set indeterminate'); - break; - default: - this.archivedFilter = 'unarchived'; - $('#archivedFilterCheckbox').checkbox('set unchecked'); - break; - } - switch (this.privateFilter) { - case 'public': - $('#privateFilterCheckbox').checkbox('set unchecked'); - break; - case 'private': - $('#privateFilterCheckbox').checkbox('set checked'); - break; - case 'both': - $('#privateFilterCheckbox').checkbox('set indeterminate'); - break; - default: - this.privateFilter = 'both'; - $('#privateFilterCheckbox').checkbox('set indeterminate'); - break; - } - }, - - changeReposFilter(filter) { - this.reposFilter = filter; - this.repos = []; - this.page = 1; - Vue.set(this.counts, `${filter}:${this.archivedFilter}:${this.privateFilter}`, 0); - this.searchRepos(); - }, - - updateHistory() { - const params = new URLSearchParams(window.location.search); - - if (this.tab === 'repos') { - params.delete('repo-search-tab'); - } else { - params.set('repo-search-tab', this.tab); - } - - if (this.reposFilter === 'all') { - params.delete('repo-search-filter'); - } else { - params.set('repo-search-filter', this.reposFilter); - } - - if (this.privateFilter === 'both') { - params.delete('repo-search-private'); - } else { - params.set('repo-search-private', this.privateFilter); - } - - if (this.archivedFilter === 'unarchived') { - params.delete('repo-search-archived'); - } else { - params.set('repo-search-archived', this.archivedFilter); - } - - if (this.searchQuery === '') { - params.delete('repo-search-query'); - } else { - params.set('repo-search-query', this.searchQuery); - } - - if (this.page === 1) { - params.delete('repo-search-page'); - } else { - params.set('repo-search-page', `${this.page}`); - } - - const queryString = params.toString(); - if (queryString) { - window.history.replaceState({}, '', `?${queryString}`); - } else { - window.history.replaceState({}, '', window.location.pathname); - } - }, - - toggleArchivedFilter() { - switch (this.archivedFilter) { - case 'both': - this.archivedFilter = 'unarchived'; - break; - case 'unarchived': - this.archivedFilter = 'archived'; - break; - case 'archived': - this.archivedFilter = 'both'; - break; - default: - this.archivedFilter = 'unarchived'; - break; - } - this.page = 1; - this.repos = []; - this.setCheckboxes(); - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0); - this.searchRepos(); - }, - - togglePrivateFilter() { - switch (this.privateFilter) { - case 'both': - this.privateFilter = 'public'; - break; - case 'public': - this.privateFilter = 'private'; - break; - case 'private': - this.privateFilter = 'both'; - break; - default: - this.privateFilter = 'both'; - break; - } - this.page = 1; - this.repos = []; - this.setCheckboxes(); - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0); - this.searchRepos(); - }, - - - changePage(page) { - this.page = page; - if (this.page > this.finalPage) { - this.page = this.finalPage; - } - if (this.page < 1) { - this.page = 1; - } - this.repos = []; - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0); - this.searchRepos(); - }, - - searchRepos() { - this.isLoading = true; - - if (!this.reposTotalCount) { - const totalCountSearchURL = `${this.suburl}/api/v1/repos/search?sort=updated&order=desc&uid=${this.uid}&team_id=${this.teamId}&q=&page=1&mode=`; - $.getJSON(totalCountSearchURL, (_result, _textStatus, request) => { - this.reposTotalCount = request.getResponseHeader('X-Total-Count'); - }); - } - - const searchedMode = this.repoTypes[this.reposFilter].searchMode; - const searchedURL = this.searchURL; - const searchedQuery = this.searchQuery; - - $.getJSON(searchedURL, (result, _textStatus, request) => { - if (searchedURL === this.searchURL) { - this.repos = result.data; - const count = request.getResponseHeader('X-Total-Count'); - if (searchedQuery === '' && searchedMode === '' && this.archivedFilter === 'both') { - this.reposTotalCount = count; - } - Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, count); - this.finalPage = Math.ceil(count / this.searchLimit); - this.updateHistory(); - } - }).always(() => { - if (searchedURL === this.searchURL) { - this.isLoading = false; - } - }); - }, - - repoIcon(repo) { - if (repo.fork) { - return 'octicon-repo-forked'; - } else if (repo.mirror) { - return 'octicon-mirror'; - } else if (repo.template) { - return `octicon-repo-template`; - } else if (repo.private) { - return 'octicon-lock'; - } else if (repo.internal) { - return 'octicon-repo'; - } - return 'octicon-repo'; - } - } - }); -} - function initCtrlEnterSubmit() { $('.js-quick-submit').on('keydown', function (e) { if (((e.ctrlKey && !e.altKey) || e.metaKey) && (e.keyCode === 13 || e.keyCode === 10)) { @@ -3476,31 +3113,6 @@ function initCtrlEnterSubmit() { }); } -function initVueApp() { - const el = document.getElementById('app'); - if (!el) { - return; - } - - initVueComponents(); - - new Vue({ - el, - delimiters: ['${', '}'], - components: { - ActivityTopAuthors, - }, - data: () => { - return { - searchLimit: Number((document.querySelector('meta[name=_search_limit]') || {}).content), - suburl: AppSubUrl, - uid: Number((document.querySelector('meta[name=_context_uid]') || {}).content), - activityTopAuthors: window.ActivityTopAuthors || [], - }; - }, - }); -} - function initIssueTimetracking() { $(document).on('click', '.issue-add-time', () => { $('.issue-start-time-modal').modal({ @@ -3543,163 +3155,6 @@ function initBranchOrTagDropdown(selector) { }); } -function initFilterBranchTagDropdown(selector) { - $(selector).each(function () { - const $dropdown = $(this); - const $data = $dropdown.find('.data'); - const data = { - items: [], - mode: $data.data('mode'), - searchTerm: '', - noResults: '', - canCreateBranch: false, - menuVisible: false, - createTag: false, - active: 0 - }; - $data.find('.item').each(function () { - data.items.push({ - name: $(this).text(), - url: $(this).data('url'), - branch: $(this).hasClass('branch'), - tag: $(this).hasClass('tag'), - selected: $(this).hasClass('selected') - }); - }); - $data.remove(); - new Vue({ - el: this, - delimiters: ['${', '}'], - data, - computed: { - filteredItems() { - const items = this.items.filter((item) => { - return ((this.mode === 'branches' && item.branch) || (this.mode === 'tags' && item.tag)) && - (!this.searchTerm || item.name.toLowerCase().includes(this.searchTerm.toLowerCase())); - }); - - // no idea how to fix this so linting rule is disabled instead - this.active = (items.length === 0 && this.showCreateNewBranch ? 0 : -1); // eslint-disable-line vue/no-side-effects-in-computed-properties - return items; - }, - showNoResults() { - return this.filteredItems.length === 0 && !this.showCreateNewBranch; - }, - showCreateNewBranch() { - if (!this.canCreateBranch || !this.searchTerm) { - return false; - } - - return this.items.filter((item) => item.name.toLowerCase() === this.searchTerm.toLowerCase()).length === 0; - } - }, - - watch: { - menuVisible(visible) { - if (visible) { - this.focusSearchField(); - } - } - }, - - beforeMount() { - this.noResults = this.$el.getAttribute('data-no-results'); - this.canCreateBranch = this.$el.getAttribute('data-can-create-branch') === 'true'; - - document.body.addEventListener('click', (event) => { - if (this.$el.contains(event.target)) return; - if (this.menuVisible) { - Vue.set(this, 'menuVisible', false); - } - }); - }, - - methods: { - selectItem(item) { - const prev = this.getSelected(); - if (prev !== null) { - prev.selected = false; - } - item.selected = true; - window.location.href = item.url; - }, - createNewBranch() { - if (!this.showCreateNewBranch) return; - $(this.$refs.newBranchForm).trigger('submit'); - }, - focusSearchField() { - Vue.nextTick(() => { - this.$refs.searchField.focus(); - }); - }, - getSelected() { - for (let i = 0, j = this.items.length; i < j; ++i) { - if (this.items[i].selected) return this.items[i]; - } - return null; - }, - getSelectedIndexInFiltered() { - for (let i = 0, j = this.filteredItems.length; i < j; ++i) { - if (this.filteredItems[i].selected) return i; - } - return -1; - }, - scrollToActive() { - let el = this.$refs[`listItem${this.active}`]; - if (!el || !el.length) return; - if (Array.isArray(el)) { - el = el[0]; - } - - const cont = this.$refs.scrollContainer; - if (el.offsetTop < cont.scrollTop) { - cont.scrollTop = el.offsetTop; - } else if (el.offsetTop + el.clientHeight > cont.scrollTop + cont.clientHeight) { - cont.scrollTop = el.offsetTop + el.clientHeight - cont.clientHeight; - } - }, - keydown(event) { - if (event.keyCode === 40) { // arrow down - event.preventDefault(); - - if (this.active === -1) { - this.active = this.getSelectedIndexInFiltered(); - } - - if (this.active + (this.showCreateNewBranch ? 0 : 1) >= this.filteredItems.length) { - return; - } - this.active++; - this.scrollToActive(); - } else if (event.keyCode === 38) { // arrow up - event.preventDefault(); - - if (this.active === -1) { - this.active = this.getSelectedIndexInFiltered(); - } - - if (this.active <= 0) { - return; - } - this.active--; - this.scrollToActive(); - } else if (event.keyCode === 13) { // enter - event.preventDefault(); - - if (this.active >= this.filteredItems.length) { - this.createNewBranch(); - } else if (this.active >= 0) { - this.selectItem(this.filteredItems[this.active]); - } - } else if (event.keyCode === 27) { // escape - event.preventDefault(); - this.menuVisible = false; - } - } - } - }); - }); -} $('.commit-button').on('click', function (e) { e.preventDefault(); |