aboutsummaryrefslogtreecommitdiffstats
path: root/web_src/js/index.js
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2021-10-15 10:35:26 +0800
committerGitHub <noreply@github.com>2021-10-15 10:35:26 +0800
commit56362043d35d2542c6fe4ac7c0ac5aabb833a9ed (patch)
treed3dd12505e7dd1b2d854c61384e1088f6901bab6 /web_src/js/index.js
parent96ff3e310f0ba1e94f4e8206758b583719a9b46c (diff)
downloadgitea-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.js567
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();