From bb71ceeeb24a7d3e768ace8075b7dcc5c13713df Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 9 Nov 2021 17:27:25 +0800 Subject: Improve async/await usage, and sort init calls in `index.js` (#17386) * clean up async/await, and sort init calls in `index.js * use `const _promise` to indicate that we do not need await an async function --- web_src/js/features/common-global.js | 4 +- web_src/js/features/comp/SearchUserBox.js | 2 +- web_src/js/features/comp/WebHookEditor.js | 2 +- web_src/js/features/diff.js | 24 ---- web_src/js/features/dropzone.js | 1 - web_src/js/features/gitgraph.js | 133 ------------------ web_src/js/features/heatmap.js | 4 +- web_src/js/features/imagediff.js | 2 +- web_src/js/features/issue-content-history.js | 135 ------------------- web_src/js/features/lastcommitloader.js | 40 ------ web_src/js/features/migration.js | 60 --------- web_src/js/features/notification.js | 4 +- web_src/js/features/projects.js | 188 -------------------------- web_src/js/features/repo-commit.js | 41 ++++++ web_src/js/features/repo-diff.js | 25 ++++ web_src/js/features/repo-editor.js | 82 +++++------ web_src/js/features/repo-graph.js | 133 ++++++++++++++++++ web_src/js/features/repo-issue-content.js | 135 +++++++++++++++++++ web_src/js/features/repo-legacy.js | 4 +- web_src/js/features/repo-migration.js | 60 +++++++++ web_src/js/features/repo-projects.js | 194 +++++++++++++++++++++++++++ web_src/js/features/repo-settings.js | 4 +- web_src/js/features/stopwatch.js | 4 +- web_src/js/index.js | 147 ++++++++++---------- web_src/js/markup/content.js | 4 +- 25 files changed, 722 insertions(+), 710 deletions(-) delete mode 100644 web_src/js/features/diff.js delete mode 100644 web_src/js/features/gitgraph.js delete mode 100644 web_src/js/features/issue-content-history.js delete mode 100644 web_src/js/features/lastcommitloader.js delete mode 100644 web_src/js/features/migration.js delete mode 100644 web_src/js/features/projects.js create mode 100644 web_src/js/features/repo-graph.js create mode 100644 web_src/js/features/repo-issue-content.js create mode 100644 web_src/js/features/repo-migration.js create mode 100644 web_src/js/features/repo-projects.js (limited to 'web_src/js') diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 04d44d8142..da3fb9d1e3 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -135,11 +135,11 @@ export function initGlobalCommon() { }); } -export async function initGlobalDropzone() { +export function initGlobalDropzone() { // Dropzone for (const el of document.querySelectorAll('.dropzone')) { const $dropzone = $(el); - await createDropzone(el, { + const _promise = createDropzone(el, { url: $dropzone.data('upload-url'), headers: {'X-Csrf-Token': csrfToken}, maxFiles: $dropzone.data('max-file'), diff --git a/web_src/js/features/comp/SearchUserBox.js b/web_src/js/features/comp/SearchUserBox.js index 0e7d122391..1382c7060d 100644 --- a/web_src/js/features/comp/SearchUserBox.js +++ b/web_src/js/features/comp/SearchUserBox.js @@ -2,7 +2,7 @@ import {htmlEscape} from 'escape-goat'; const {appSubUrl} = window.config; -export function initSearchUserBox() { +export function initCompSearchUserBox() { const $searchUserBox = $('#search-user-box'); $searchUserBox.search({ minCharacters: 2, diff --git a/web_src/js/features/comp/WebHookEditor.js b/web_src/js/features/comp/WebHookEditor.js index ddff73ee37..efef10ad64 100644 --- a/web_src/js/features/comp/WebHookEditor.js +++ b/web_src/js/features/comp/WebHookEditor.js @@ -1,6 +1,6 @@ const {csrfToken} = window.config; -export function initWebHookEditor() { +export function initCompWebHookEditor() { if ($('.new.webhook').length === 0) { return; } diff --git a/web_src/js/features/diff.js b/web_src/js/features/diff.js deleted file mode 100644 index ef0aaceeeb..0000000000 --- a/web_src/js/features/diff.js +++ /dev/null @@ -1,24 +0,0 @@ -export function initDiffShowMore() { - $('#diff-files, #diff-file-boxes').on('click', '#diff-show-more-files, #diff-show-more-files-stats', (e) => { - e.preventDefault(); - - if ($(e.target).hasClass('disabled')) { - return; - } - $('#diff-show-more-files, #diff-show-more-files-stats').addClass('disabled'); - - const url = $('#diff-show-more-files, #diff-show-more-files-stats').data('href'); - $.ajax({ - type: 'GET', - url, - }).done((resp) => { - if (!resp || resp.html === '' || resp.empty) { - $('#diff-show-more-files, #diff-show-more-files-stats').removeClass('disabled'); - return; - } - $('#diff-too-many-files-stats').remove(); - $('#diff-files').append($(resp).find('#diff-files li')); - $('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children()); - }); - }); -} diff --git a/web_src/js/features/dropzone.js b/web_src/js/features/dropzone.js index 6a4f7e17e4..f3c3a1415f 100644 --- a/web_src/js/features/dropzone.js +++ b/web_src/js/features/dropzone.js @@ -3,7 +3,6 @@ export default async function createDropzone(el, opts) { import(/* webpackChunkName: "dropzone" */'dropzone'), import(/* webpackChunkName: "dropzone" */'dropzone/dist/dropzone.css'), ]); - Dropzone.autoDiscover = false; return new Dropzone(el, opts); } diff --git a/web_src/js/features/gitgraph.js b/web_src/js/features/gitgraph.js deleted file mode 100644 index cd2668ad35..0000000000 --- a/web_src/js/features/gitgraph.js +++ /dev/null @@ -1,133 +0,0 @@ -export default async function initGitGraph() { - const graphContainer = document.getElementById('git-graph-container'); - if (!graphContainer) return; - - $('#flow-color-monochrome').on('click', () => { - $('#flow-color-monochrome').addClass('active'); - $('#flow-color-colored').removeClass('active'); - $('#git-graph-container').removeClass('colored').addClass('monochrome'); - const params = new URLSearchParams(window.location.search); - params.set('mode', 'monochrome'); - const queryString = params.toString(); - if (queryString) { - window.history.replaceState({}, '', `?${queryString}`); - } else { - window.history.replaceState({}, '', window.location.pathname); - } - $('.pagination a').each((_, that) => { - const href = $(that).attr('href'); - if (!href) return; - const url = new URL(href, window.location); - const params = url.searchParams; - params.set('mode', 'monochrome'); - url.search = `?${params.toString()}`; - $(that).attr('href', url.href); - }); - }); - $('#flow-color-colored').on('click', () => { - $('#flow-color-colored').addClass('active'); - $('#flow-color-monochrome').removeClass('active'); - $('#git-graph-container').addClass('colored').removeClass('monochrome'); - $('.pagination a').each((_, that) => { - const href = $(that).attr('href'); - if (!href) return; - const url = new URL(href, window.location); - const params = url.searchParams; - params.delete('mode'); - url.search = `?${params.toString()}`; - $(that).attr('href', url.href); - }); - const params = new URLSearchParams(window.location.search); - params.delete('mode'); - const queryString = params.toString(); - if (queryString) { - window.history.replaceState({}, '', `?${queryString}`); - } else { - window.history.replaceState({}, '', window.location.pathname); - } - }); - const url = new URL(window.location); - const params = url.searchParams; - const updateGraph = async () => { - const queryString = params.toString(); - const ajaxUrl = new URL(url); - ajaxUrl.searchParams.set('div-only', 'true'); - window.history.replaceState({}, '', queryString ? `?${queryString}` : window.location.pathname); - $('#pagination').empty(); - $('#rel-container').addClass('hide'); - $('#rev-container').addClass('hide'); - $('#loading-indicator').removeClass('hide'); - - const div = $(await $.ajax(String(ajaxUrl))); - $('#pagination').html(div.find('#pagination').html()); - $('#rel-container').html(div.find('#rel-container').html()); - $('#rev-container').html(div.find('#rev-container').html()); - $('#loading-indicator').addClass('hide'); - $('#rel-container').removeClass('hide'); - $('#rev-container').removeClass('hide'); - }; - const dropdownSelected = params.getAll('branch'); - if (params.has('hide-pr-refs') && params.get('hide-pr-refs') === 'true') { - dropdownSelected.splice(0, 0, '...flow-hide-pr-refs'); - } - - $('#flow-select-refs-dropdown').dropdown('set selected', dropdownSelected); - $('#flow-select-refs-dropdown').dropdown({ - clearable: true, - fullTextSeach: 'exact', - onRemove(toRemove) { - if (toRemove === '...flow-hide-pr-refs') { - params.delete('hide-pr-refs'); - } else { - const branches = params.getAll('branch'); - params.delete('branch'); - for (const branch of branches) { - if (branch !== toRemove) { - params.append('branch', branch); - } - } - } - updateGraph(); - }, - onAdd(toAdd) { - if (toAdd === '...flow-hide-pr-refs') { - params.set('hide-pr-refs', true); - } else { - params.append('branch', toAdd); - } - updateGraph(); - }, - }); - $('#git-graph-container').on('mouseenter', '#rev-list li', (e) => { - const flow = $(e.currentTarget).data('flow'); - if (flow === 0) return; - $(`#flow-${flow}`).addClass('highlight'); - $(e.currentTarget).addClass('hover'); - $(`#rev-list li[data-flow='${flow}']`).addClass('highlight'); - }); - $('#git-graph-container').on('mouseleave', '#rev-list li', (e) => { - const flow = $(e.currentTarget).data('flow'); - if (flow === 0) return; - $(`#flow-${flow}`).removeClass('highlight'); - $(e.currentTarget).removeClass('hover'); - $(`#rev-list li[data-flow='${flow}']`).removeClass('highlight'); - }); - $('#git-graph-container').on('mouseenter', '#rel-container .flow-group', (e) => { - $(e.currentTarget).addClass('highlight'); - const flow = $(e.currentTarget).data('flow'); - $(`#rev-list li[data-flow='${flow}']`).addClass('highlight'); - }); - $('#git-graph-container').on('mouseleave', '#rel-container .flow-group', (e) => { - $(e.currentTarget).removeClass('highlight'); - const flow = $(e.currentTarget).data('flow'); - $(`#rev-list li[data-flow='${flow}']`).removeClass('highlight'); - }); - $('#git-graph-container').on('mouseenter', '#rel-container .flow-commit', (e) => { - const rev = $(e.currentTarget).data('rev'); - $(`#rev-list li#commit-${rev}`).addClass('hover'); - }); - $('#git-graph-container').on('mouseleave', '#rel-container .flow-commit', (e) => { - const rev = $(e.currentTarget).data('rev'); - $(`#rev-list li#commit-${rev}`).removeClass('hover'); - }); -} diff --git a/web_src/js/features/heatmap.js b/web_src/js/features/heatmap.js index 07ecaee461..52b7517c1a 100644 --- a/web_src/js/features/heatmap.js +++ b/web_src/js/features/heatmap.js @@ -2,7 +2,7 @@ import Vue from 'vue'; import ActivityHeatmap from '../components/ActivityHeatmap.vue'; -export default async function initHeatmap() { +export default function initHeatmap() { const el = document.getElementById('user-heatmap'); if (!el) return; @@ -24,7 +24,7 @@ export default async function initHeatmap() { new View().$mount(el); } catch (err) { - console.error(err); + console.error('Heatmap failed to load', err); el.textContent = 'Heatmap failed to load'; } } diff --git a/web_src/js/features/imagediff.js b/web_src/js/features/imagediff.js index 67e9548596..d3f90b6260 100644 --- a/web_src/js/features/imagediff.js +++ b/web_src/js/features/imagediff.js @@ -29,7 +29,7 @@ function getDefaultSvgBoundsIfUndefined(svgXml, src) { } } -export default async function initImageDiff() { +export default function initImageDiff() { function createContext(image1, image2) { const size1 = { width: image1 && image1.width || 0, diff --git a/web_src/js/features/issue-content-history.js b/web_src/js/features/issue-content-history.js deleted file mode 100644 index c71d3789d4..0000000000 --- a/web_src/js/features/issue-content-history.js +++ /dev/null @@ -1,135 +0,0 @@ -import {svg} from '../svg.js'; - -const {appSubUrl, csrfToken} = window.config; - -let i18nTextEdited; -let i18nTextOptions; -let i18nTextDeleteFromHistory; -let i18nTextDeleteFromHistoryConfirm; - -function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleHtml) { - let $dialog = $('.content-history-detail-dialog'); - if ($dialog.length) return; - - $dialog = $(` -`); - $dialog.appendTo($('body')); - $dialog.find('.dialog-header-options').dropdown({ - showOnFocus: false, - allowReselection: true, - onChange(_value, _text, $item) { - const optionItem = $item.data('option-item'); - if (optionItem === 'delete') { - if (window.confirm(i18nTextDeleteFromHistoryConfirm)) { - $.post(`${issueBaseUrl}/content-history/soft-delete?comment_id=${commentId}&history_id=${historyId}`, { - _csrf: csrfToken, - }).done((resp) => { - if (resp.ok) { - $dialog.modal('hide'); - } else { - alert(resp.message); - } - }); - } - } else { // required by eslint - window.alert(`unknown option item: ${optionItem}`); - } - }, - onHide() { - $(this).dropdown('clear', true); - } - }); - $dialog.modal({ - onShow() { - $.ajax({ - url: `${issueBaseUrl}/content-history/detail?comment_id=${commentId}&history_id=${historyId}`, - data: { - _csrf: csrfToken, - }, - }).done((resp) => { - $dialog.find('.content').html(resp.diffHtml); - // there is only one option "item[data-option-item=delete]", so the dropdown can be entirely shown/hidden. - if (resp.canSoftDelete) { - $dialog.find('.dialog-header-options').show(); - } - }); - }, - onHidden() { - $dialog.remove(); - }, - }).modal('show'); -} - -function showContentHistoryMenu(issueBaseUrl, $item, commentId) { - const $headerLeft = $item.find('.comment-header-left'); - const menuHtml = ` - `; - - $headerLeft.find(`.content-history-menu`).remove(); - $headerLeft.append($(menuHtml)); - $headerLeft.find('.dropdown').dropdown({ - action: 'hide', - apiSettings: { - cache: false, - url: `${issueBaseUrl}/content-history/list?comment_id=${commentId}`, - }, - saveRemoteData: false, - onHide() { - $(this).dropdown('change values', null); - }, - onChange(value, itemHtml, $item) { - if (value && !$item.find('[data-history-is-deleted=1]').length) { - showContentHistoryDetail(issueBaseUrl, commentId, value, itemHtml); - } - }, - }); -} - -export function initIssueContentHistory() { - const issueIndex = $('#issueIndex').val(); - const $itemIssue = $('.timeline-item.comment.first'); - if (!issueIndex || !$itemIssue.length) return; - - const repoLink = $('#repolink').val(); - const issueBaseUrl = `${appSubUrl}/${repoLink}/issues/${issueIndex}`; - - $.ajax({ - url: `${issueBaseUrl}/content-history/overview`, - data: { - _csrf: csrfToken, - }, - }).done((resp) => { - i18nTextEdited = resp.i18n.textEdited; - i18nTextDeleteFromHistory = resp.i18n.textDeleteFromHistory; - i18nTextDeleteFromHistoryConfirm = resp.i18n.textDeleteFromHistoryConfirm; - i18nTextOptions = resp.i18n.textOptions; - - if (resp.editedHistoryCountMap[0]) { - showContentHistoryMenu(issueBaseUrl, $itemIssue, '0'); - } - for (const [commentId, _editedCount] of Object.entries(resp.editedHistoryCountMap)) { - if (commentId === '0') continue; - const $itemComment = $(`#issuecomment-${commentId}`); - showContentHistoryMenu(issueBaseUrl, $itemComment, commentId); - } - }); -} diff --git a/web_src/js/features/lastcommitloader.js b/web_src/js/features/lastcommitloader.js deleted file mode 100644 index 04e1e452ae..0000000000 --- a/web_src/js/features/lastcommitloader.js +++ /dev/null @@ -1,40 +0,0 @@ -const {csrfToken} = window.config; - -export async function initLastCommitLoader() { - const entryMap = {}; - - const entries = $('table#repo-files-table tr.notready') - .map((_, v) => { - entryMap[$(v).attr('data-entryname')] = $(v); - return $(v).attr('data-entryname'); - }) - .get(); - - if (entries.length === 0) { - return; - } - - const lastCommitLoaderURL = $('table#repo-files-table').data('lastCommitLoaderUrl'); - - if (entries.length > 200) { - $.post(lastCommitLoaderURL, { - _csrf: csrfToken, - }, (data) => { - $('table#repo-files-table').replaceWith(data); - }); - return; - } - - $.post(lastCommitLoaderURL, { - _csrf: csrfToken, - 'f': entries, - }, (data) => { - $(data).find('tr').each((_, row) => { - if (row.className === 'commit-list') { - $('table#repo-files-table .commit-list').replaceWith(row); - return; - } - entryMap[$(row).attr('data-entryname')].replaceWith(row); - }); - }); -} diff --git a/web_src/js/features/migration.js b/web_src/js/features/migration.js deleted file mode 100644 index d41dc3c1cd..0000000000 --- a/web_src/js/features/migration.js +++ /dev/null @@ -1,60 +0,0 @@ -const $service = $('#service_type'); -const $user = $('#auth_username'); -const $pass = $('#auth_password'); -const $token = $('#auth_token'); -const $mirror = $('#mirror'); -const $lfs = $('#lfs'); -const $lfsSettings = $('#lfs_settings'); -const $lfsEndpoint = $('#lfs_endpoint'); -const $items = $('#migrate_items').find('input[type=checkbox]'); - -export default function initMigration() { - checkAuth(); - setLFSSettingsVisibility(); - - $user.on('keyup', () => {checkItems(false)}); - $pass.on('keyup', () => {checkItems(false)}); - $token.on('keyup', () => {checkItems(true)}); - $mirror.on('change', () => {checkItems(true)}); - $('#lfs_settings_show').on('click', () => { $lfsEndpoint.show(); return false }); - $lfs.on('change', setLFSSettingsVisibility); - - const $cloneAddr = $('#clone_addr'); - $cloneAddr.on('change', () => { - const $repoName = $('#repo_name'); - if ($cloneAddr.val().length > 0 && $repoName.val().length === 0) { // Only modify if repo_name input is blank - $repoName.val($cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]); - } - }); -} - -function checkAuth() { - const serviceType = $service.val(); - - checkItems(serviceType !== 1); -} - -function checkItems(tokenAuth) { - let enableItems; - if (tokenAuth) { - enableItems = $token.val() !== ''; - } else { - enableItems = $user.val() !== '' || $pass.val() !== ''; - } - if (enableItems && $service.val() > 1) { - if ($mirror.is(':checked')) { - $items.not('[name="wiki"]').attr('disabled', true); - $items.filter('[name="wiki"]').attr('disabled', false); - return; - } - $items.attr('disabled', false); - } else { - $items.attr('disabled', true); - } -} - -function setLFSSettingsVisibility() { - const visible = $lfs.is(':checked'); - $lfsSettings.toggle(visible); - $lfsEndpoint.hide(); -} diff --git a/web_src/js/features/notification.js b/web_src/js/features/notification.js index 71ebb538d4..f4c31c5ede 100644 --- a/web_src/js/features/notification.js +++ b/web_src/js/features/notification.js @@ -40,7 +40,7 @@ async function receiveUpdateCount(event) { } } -export async function initNotificationCount() { +export function initNotificationCount() { const notificationCount = $('.notification_count'); if (!notificationCount.length) { @@ -66,7 +66,7 @@ export async function initNotificationCount() { return; } if (event.data.type === 'notification-count') { - receiveUpdateCount(event.data); + const _promise = receiveUpdateCount(event.data); } else if (event.data.type === 'error') { console.error(event.data); } else if (event.data.type === 'logout') { diff --git a/web_src/js/features/projects.js b/web_src/js/features/projects.js deleted file mode 100644 index 736c09661d..0000000000 --- a/web_src/js/features/projects.js +++ /dev/null @@ -1,188 +0,0 @@ -const {csrfToken} = window.config; - -export default async function initProject() { - if (!$('.repository.projects').length) { - return; - } - - const {Sortable} = await import(/* webpackChunkName: "sortable" */'sortablejs'); - const boardColumns = document.getElementsByClassName('board-column'); - - new Sortable( - document.getElementsByClassName('board')[0], - { - group: 'board-column', - draggable: '.board-column', - animation: 150, - ghostClass: 'card-ghost', - onSort: () => { - const board = document.getElementsByClassName('board')[0]; - const boardColumns = board.getElementsByClassName('board-column'); - - boardColumns.forEach((column, i) => { - if (parseInt($(column).data('sorting')) !== i) { - $.ajax({ - url: $(column).data('url'), - data: JSON.stringify({sorting: i, color: rgbToHex($(column).css('backgroundColor'))}), - headers: { - 'X-Csrf-Token': csrfToken, - 'X-Remote': true, - }, - contentType: 'application/json', - method: 'PUT', - }); - } - }); - }, - }, - ); - - for (const column of boardColumns) { - new Sortable( - column.getElementsByClassName('board')[0], - { - group: 'shared', - animation: 150, - ghostClass: 'card-ghost', - onAdd: (e) => { - $.ajax(`${e.to.dataset.url}/${e.item.dataset.issue}`, { - headers: { - 'X-Csrf-Token': csrfToken, - 'X-Remote': true, - }, - contentType: 'application/json', - type: 'POST', - error: () => { - e.from.insertBefore(e.item, e.from.children[e.oldIndex]); - }, - }); - }, - }, - ); - } - - $('.edit-project-board').each(function () { - const projectHeader = $(this).closest('.board-column-header'); - const projectTitleLabel = projectHeader.find('.board-label'); - const projectTitleInput = $(this).find( - '.content > .form > .field > .project-board-title', - ); - const projectColorInput = $(this).find('.content > .form > .field #new_board_color'); - const boardColumn = $(this).closest('.board-column'); - - if (boardColumn.css('backgroundColor')) { - setLabelColor(projectHeader, rgbToHex(boardColumn.css('backgroundColor'))); - } - - $(this) - .find('.content > .form > .actions > .red') - .on('click', function (e) { - e.preventDefault(); - - $.ajax({ - url: $(this).data('url'), - data: JSON.stringify({title: projectTitleInput.val(), color: projectColorInput.val()}), - headers: { - 'X-Csrf-Token': csrfToken, - 'X-Remote': true, - }, - contentType: 'application/json', - method: 'PUT', - }).done(() => { - projectTitleLabel.text(projectTitleInput.val()); - projectTitleInput.closest('form').removeClass('dirty'); - if (projectColorInput.val()) { - setLabelColor(projectHeader, projectColorInput.val()); - } - boardColumn.attr('style', `background: ${projectColorInput.val()}!important`); - $('.ui.modal').modal('hide'); - }); - }); - }); - - $(document).on('click', '.set-default-project-board', async function (e) { - e.preventDefault(); - - await $.ajax({ - method: 'POST', - url: $(this).data('url'), - headers: { - 'X-Csrf-Token': csrfToken, - 'X-Remote': true, - }, - contentType: 'application/json', - }); - - window.location.reload(); - }); - - $('.delete-project-board').each(function () { - $(this).click(function (e) { - e.preventDefault(); - - $.ajax({ - url: $(this).data('url'), - headers: { - 'X-Csrf-Token': csrfToken, - 'X-Remote': true, - }, - contentType: 'application/json', - method: 'DELETE', - }).done(() => { - window.location.reload(); - }); - }); - }); - - $('#new_board_submit').click(function (e) { - e.preventDefault(); - - const boardTitle = $('#new_board'); - const projectColorInput = $('#new_board_color_picker'); - - $.ajax({ - url: $(this).data('url'), - data: JSON.stringify({title: boardTitle.val(), color: projectColorInput.val()}), - headers: { - 'X-Csrf-Token': csrfToken, - 'X-Remote': true, - }, - contentType: 'application/json', - method: 'POST', - }).done(() => { - boardTitle.closest('form').removeClass('dirty'); - window.location.reload(); - }); - }); -} - -function setLabelColor(label, color) { - const red = getRelativeColor(parseInt(color.substr(1, 2), 16)); - const green = getRelativeColor(parseInt(color.substr(3, 2), 16)); - const blue = getRelativeColor(parseInt(color.substr(5, 2), 16)); - const luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue; - - if (luminance > 0.179) { - label.removeClass('light-label').addClass('dark-label'); - } else { - label.removeClass('dark-label').addClass('light-label'); - } -} - -/** - * Inspired by W3C recommandation https://www.w3.org/TR/WCAG20/#relativeluminancedef - */ -function getRelativeColor(color) { - color /= 255; - return color <= 0.03928 ? color / 12.92 : ((color + 0.055) / 1.055) ** 2.4; -} - -function rgbToHex(rgb) { - rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); - return `#${hex(rgb[1])}${hex(rgb[2])}${hex(rgb[3])}`; -} - -function hex(x) { - const hexDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; - return Number.isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16]; -} diff --git a/web_src/js/features/repo-commit.js b/web_src/js/features/repo-commit.js index 336a37d654..847fed3f1d 100644 --- a/web_src/js/features/repo-commit.js +++ b/web_src/js/features/repo-commit.js @@ -1,6 +1,47 @@ +const {csrfToken} = window.config; + export function initRepoCommitButton() { $('.commit-button').on('click', function (e) { e.preventDefault(); $(this).parent().find('.commit-body').toggle(); }); } + +export function initRepoCommitLastCommitLoader() { + const entryMap = {}; + + const entries = $('table#repo-files-table tr.notready') + .map((_, v) => { + entryMap[$(v).attr('data-entryname')] = $(v); + return $(v).attr('data-entryname'); + }) + .get(); + + if (entries.length === 0) { + return; + } + + const lastCommitLoaderURL = $('table#repo-files-table').data('lastCommitLoaderUrl'); + + if (entries.length > 200) { + $.post(lastCommitLoaderURL, { + _csrf: csrfToken, + }, (data) => { + $('table#repo-files-table').replaceWith(data); + }); + return; + } + + $.post(lastCommitLoaderURL, { + _csrf: csrfToken, + 'f': entries, + }, (data) => { + $(data).find('tr').each((_, row) => { + if (row.className === 'commit-list') { + $('table#repo-files-table .commit-list').replaceWith(row); + return; + } + entryMap[$(row).attr('data-entryname')].replaceWith(row); + }); + }); +} diff --git a/web_src/js/features/repo-diff.js b/web_src/js/features/repo-diff.js index c3fb78a683..76355615c6 100644 --- a/web_src/js/features/repo-diff.js +++ b/web_src/js/features/repo-diff.js @@ -79,3 +79,28 @@ export function initRepoDiffConversationNav() { window.location.href = `#${anchor}`; }); } + +export function initRepoDiffShowMore() { + $('#diff-files, #diff-file-boxes').on('click', '#diff-show-more-files, #diff-show-more-files-stats', (e) => { + e.preventDefault(); + + if ($(e.target).hasClass('disabled')) { + return; + } + $('#diff-show-more-files, #diff-show-more-files-stats').addClass('disabled'); + + const url = $('#diff-show-more-files, #diff-show-more-files-stats').data('href'); + $.ajax({ + type: 'GET', + url, + }).done((resp) => { + if (!resp || resp.html === '' || resp.empty) { + $('#diff-show-more-files, #diff-show-more-files-stats').removeClass('disabled'); + return; + } + $('#diff-too-many-files-stats').remove(); + $('#diff-files').append($(resp).find('#diff-files li')); + $('#diff-incomplete').replaceWith($(resp).find('#diff-file-boxes').children()); + }); + }); +} diff --git a/web_src/js/features/repo-editor.js b/web_src/js/features/repo-editor.js index e2acaafd12..7bf401207a 100644 --- a/web_src/js/features/repo-editor.js +++ b/web_src/js/features/repo-editor.js @@ -24,7 +24,7 @@ function initEditPreviewTab($form) { _csrf: csrfToken, mode, context, - text: $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val() + text: $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val(), }, (data) => { const $previewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('preview')}"]`); $previewPanel.html(data); @@ -42,7 +42,7 @@ function initEditDiffTab($form) { $.post($this.data('url'), { _csrf: csrfToken, context: $this.data('context'), - content: $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val() + content: $form.find(`.tab[data-tab="${$tabMenu.data('write')}"] textarea`).val(), }, (data) => { const $diffPreviewPanel = $form.find(`.tab[data-tab="${$tabMenu.data('diff')}"]`); $diffPreviewPanel.html(data); @@ -75,7 +75,7 @@ function getCursorPosition($e) { return pos; } -export async function initRepoEditor() { +export function initRepoEditor() { initEditorForm(); $('.js-quick-pull-choice-option').on('change', function () { @@ -134,47 +134,49 @@ export async function initRepoEditor() { const $editArea = $('.repository.editor textarea#edit_area'); if (!$editArea.length) return; - const editor = await createCodeEditor($editArea[0], $editFilename[0], previewFileModes); + (async () => { + const editor = await createCodeEditor($editArea[0], $editFilename[0], previewFileModes); - // Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage - // to enable or disable the commit button - const $commitButton = $('#commit-button'); - const $editForm = $('.ui.edit.form'); - const dirtyFileClass = 'dirty-file'; + // Using events from https://github.com/codedance/jquery.AreYouSure#advanced-usage + // to enable or disable the commit button + const $commitButton = $('#commit-button'); + const $editForm = $('.ui.edit.form'); + const dirtyFileClass = 'dirty-file'; - // Disabling the button at the start - if ($('input[name="page_has_posted"]').val() !== 'true') { - $commitButton.prop('disabled', true); - } - - // Registering a custom listener for the file path and the file content - $editForm.areYouSure({ - silent: true, - dirtyClass: dirtyFileClass, - fieldSelector: ':input:not(.commit-form-wrapper :input)', - change() { - const dirty = $(this).hasClass(dirtyFileClass); - $commitButton.prop('disabled', !dirty); + // Disabling the button at the start + if ($('input[name="page_has_posted"]').val() !== 'true') { + $commitButton.prop('disabled', true); } - }); - // Update the editor from query params, if available, - // only after the dirtyFileClass initialization - const params = new URLSearchParams(window.location.search); - const value = params.get('value'); - if (value) { - editor.setValue(value); - } + // Registering a custom listener for the file path and the file content + $editForm.areYouSure({ + silent: true, + dirtyClass: dirtyFileClass, + fieldSelector: ':input:not(.commit-form-wrapper :input)', + change() { + const dirty = $(this).hasClass(dirtyFileClass); + $commitButton.prop('disabled', !dirty); + }, + }); - $commitButton.on('click', (event) => { - // A modal which asks if an empty file should be committed - if ($editArea.val().length === 0) { - $('#edit-empty-content-modal').modal({ - onApprove() { - $('.edit.form').trigger('submit'); - } - }).modal('show'); - event.preventDefault(); + // Update the editor from query params, if available, + // only after the dirtyFileClass initialization + const params = new URLSearchParams(window.location.search); + const value = params.get('value'); + if (value) { + editor.setValue(value); } - }); + + $commitButton.on('click', (event) => { + // A modal which asks if an empty file should be committed + if ($editArea.val().length === 0) { + $('#edit-empty-content-modal').modal({ + onApprove() { + $('.edit.form').trigger('submit'); + }, + }).modal('show'); + event.preventDefault(); + } + }); + })(); } diff --git a/web_src/js/features/repo-graph.js b/web_src/js/features/repo-graph.js new file mode 100644 index 0000000000..007cf9b38d --- /dev/null +++ b/web_src/js/features/repo-graph.js @@ -0,0 +1,133 @@ +export default function initRepoGraphGit() { + const graphContainer = document.getElementById('git-graph-container'); + if (!graphContainer) return; + + $('#flow-color-monochrome').on('click', () => { + $('#flow-color-monochrome').addClass('active'); + $('#flow-color-colored').removeClass('active'); + $('#git-graph-container').removeClass('colored').addClass('monochrome'); + const params = new URLSearchParams(window.location.search); + params.set('mode', 'monochrome'); + const queryString = params.toString(); + if (queryString) { + window.history.replaceState({}, '', `?${queryString}`); + } else { + window.history.replaceState({}, '', window.location.pathname); + } + $('.pagination a').each((_, that) => { + const href = $(that).attr('href'); + if (!href) return; + const url = new URL(href, window.location); + const params = url.searchParams; + params.set('mode', 'monochrome'); + url.search = `?${params.toString()}`; + $(that).attr('href', url.href); + }); + }); + $('#flow-color-colored').on('click', () => { + $('#flow-color-colored').addClass('active'); + $('#flow-color-monochrome').removeClass('active'); + $('#git-graph-container').addClass('colored').removeClass('monochrome'); + $('.pagination a').each((_, that) => { + const href = $(that).attr('href'); + if (!href) return; + const url = new URL(href, window.location); + const params = url.searchParams; + params.delete('mode'); + url.search = `?${params.toString()}`; + $(that).attr('href', url.href); + }); + const params = new URLSearchParams(window.location.search); + params.delete('mode'); + const queryString = params.toString(); + if (queryString) { + window.history.replaceState({}, '', `?${queryString}`); + } else { + window.history.replaceState({}, '', window.location.pathname); + } + }); + const url = new URL(window.location); + const params = url.searchParams; + const updateGraph = async () => { + const queryString = params.toString(); + const ajaxUrl = new URL(url); + ajaxUrl.searchParams.set('div-only', 'true'); + window.history.replaceState({}, '', queryString ? `?${queryString}` : window.location.pathname); + $('#pagination').empty(); + $('#rel-container').addClass('hide'); + $('#rev-container').addClass('hide'); + $('#loading-indicator').removeClass('hide'); + + const div = $(await $.ajax(String(ajaxUrl))); + $('#pagination').html(div.find('#pagination').html()); + $('#rel-container').html(div.find('#rel-container').html()); + $('#rev-container').html(div.find('#rev-container').html()); + $('#loading-indicator').addClass('hide'); + $('#rel-container').removeClass('hide'); + $('#rev-container').removeClass('hide'); + }; + const dropdownSelected = params.getAll('branch'); + if (params.has('hide-pr-refs') && params.get('hide-pr-refs') === 'true') { + dropdownSelected.splice(0, 0, '...flow-hide-pr-refs'); + } + + $('#flow-select-refs-dropdown').dropdown('set selected', dropdownSelected); + $('#flow-select-refs-dropdown').dropdown({ + clearable: true, + fullTextSeach: 'exact', + onRemove(toRemove) { + if (toRemove === '...flow-hide-pr-refs') { + params.delete('hide-pr-refs'); + } else { + const branches = params.getAll('branch'); + params.delete('branch'); + for (const branch of branches) { + if (branch !== toRemove) { + params.append('branch', branch); + } + } + } + updateGraph(); + }, + onAdd(toAdd) { + if (toAdd === '...flow-hide-pr-refs') { + params.set('hide-pr-refs', true); + } else { + params.append('branch', toAdd); + } + updateGraph(); + }, + }); + $('#git-graph-container').on('mouseenter', '#rev-list li', (e) => { + const flow = $(e.currentTarget).data('flow'); + if (flow === 0) return; + $(`#flow-${flow}`).addClass('highlight'); + $(e.currentTarget).addClass('hover'); + $(`#rev-list li[data-flow='${flow}']`).addClass('highlight'); + }); + $('#git-graph-container').on('mouseleave', '#rev-list li', (e) => { + const flow = $(e.currentTarget).data('flow'); + if (flow === 0) return; + $(`#flow-${flow}`).removeClass('highlight'); + $(e.currentTarget).removeClass('hover'); + $(`#rev-list li[data-flow='${flow}']`).removeClass('highlight'); + }); + $('#git-graph-container').on('mouseenter', '#rel-container .flow-group', (e) => { + $(e.currentTarget).addClass('highlight'); + const flow = $(e.currentTarget).data('flow'); + $(`#rev-list li[data-flow='${flow}']`).addClass('highlight'); + }); + $('#git-graph-container').on('mouseleave', '#rel-container .flow-group', (e) => { + $(e.currentTarget).removeClass('highlight'); + const flow = $(e.currentTarget).data('flow'); + $(`#rev-list li[data-flow='${flow}']`).removeClass('highlight'); + }); + $('#git-graph-container').on('mouseenter', '#rel-container .flow-commit', (e) => { + const rev = $(e.currentTarget).data('rev'); + $(`#rev-list li#commit-${rev}`).addClass('hover'); + }); + $('#git-graph-container').on('mouseleave', '#rel-container .flow-commit', (e) => { + const rev = $(e.currentTarget).data('rev'); + $(`#rev-list li#commit-${rev}`).removeClass('hover'); + }); +} diff --git a/web_src/js/features/repo-issue-content.js b/web_src/js/features/repo-issue-content.js new file mode 100644 index 0000000000..a2fc6c3cbe --- /dev/null +++ b/web_src/js/features/repo-issue-content.js @@ -0,0 +1,135 @@ +import {svg} from '../svg.js'; + +const {appSubUrl, csrfToken} = window.config; + +let i18nTextEdited; +let i18nTextOptions; +let i18nTextDeleteFromHistory; +let i18nTextDeleteFromHistoryConfirm; + +function showContentHistoryDetail(issueBaseUrl, commentId, historyId, itemTitleHtml) { + let $dialog = $('.content-history-detail-dialog'); + if ($dialog.length) return; + + $dialog = $(` +`); + $dialog.appendTo($('body')); + $dialog.find('.dialog-header-options').dropdown({ + showOnFocus: false, + allowReselection: true, + onChange(_value, _text, $item) { + const optionItem = $item.data('option-item'); + if (optionItem === 'delete') { + if (window.confirm(i18nTextDeleteFromHistoryConfirm)) { + $.post(`${issueBaseUrl}/content-history/soft-delete?comment_id=${commentId}&history_id=${historyId}`, { + _csrf: csrfToken, + }).done((resp) => { + if (resp.ok) { + $dialog.modal('hide'); + } else { + alert(resp.message); + } + }); + } + } else { // required by eslint + window.alert(`unknown option item: ${optionItem}`); + } + }, + onHide() { + $(this).dropdown('clear', true); + } + }); + $dialog.modal({ + onShow() { + $.ajax({ + url: `${issueBaseUrl}/content-history/detail?comment_id=${commentId}&history_id=${historyId}`, + data: { + _csrf: csrfToken, + }, + }).done((resp) => { + $dialog.find('.content').html(resp.diffHtml); + // there is only one option "item[data-option-item=delete]", so the dropdown can be entirely shown/hidden. + if (resp.canSoftDelete) { + $dialog.find('.dialog-header-options').show(); + } + }); + }, + onHidden() { + $dialog.remove(); + }, + }).modal('show'); +} + +function showContentHistoryMenu(issueBaseUrl, $item, commentId) { + const $headerLeft = $item.find('.comment-header-left'); + const menuHtml = ` + `; + + $headerLeft.find(`.content-history-menu`).remove(); + $headerLeft.append($(menuHtml)); + $headerLeft.find('.dropdown').dropdown({ + action: 'hide', + apiSettings: { + cache: false, + url: `${issueBaseUrl}/content-history/list?comment_id=${commentId}`, + }, + saveRemoteData: false, + onHide() { + $(this).dropdown('change values', null); + }, + onChange(value, itemHtml, $item) { + if (value && !$item.find('[data-history-is-deleted=1]').length) { + showContentHistoryDetail(issueBaseUrl, commentId, value, itemHtml); + } + }, + }); +} + +export function initRepoIssueContentHistory() { + const issueIndex = $('#issueIndex').val(); + const $itemIssue = $('.timeline-item.comment.first'); + if (!issueIndex || !$itemIssue.length) return; + + const repoLink = $('#repolink').val(); + const issueBaseUrl = `${appSubUrl}/${repoLink}/issues/${issueIndex}`; + + $.ajax({ + url: `${issueBaseUrl}/content-history/overview`, + data: { + _csrf: csrfToken, + }, + }).done((resp) => { + i18nTextEdited = resp.i18n.textEdited; + i18nTextDeleteFromHistory = resp.i18n.textDeleteFromHistory; + i18nTextDeleteFromHistoryConfirm = resp.i18n.textDeleteFromHistoryConfirm; + i18nTextOptions = resp.i18n.textOptions; + + if (resp.editedHistoryCountMap[0]) { + showContentHistoryMenu(issueBaseUrl, $itemIssue, '0'); + } + for (const [commentId, _editedCount] of Object.entries(resp.editedHistoryCountMap)) { + if (commentId === '0') continue; + const $itemComment = $(`#issuecomment-${commentId}`); + showContentHistoryMenu(issueBaseUrl, $itemComment, commentId); + } + }); +} diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 6692d1902c..f4a8c0cf3e 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -259,7 +259,7 @@ export function initRepoCommentForm() { } -export async function initRepository() { +export function initRepository() { if ($('.repository').length === 0) { return; } @@ -363,7 +363,7 @@ export async function initRepository() { if ($editContentZone.html().length === 0) { $editContentZone.html($('#edit-content-form').html()); $textarea = $editContentZone.find('textarea'); - attachTribute($textarea.get(), {mentions: true, emoji: true}); + await attachTribute($textarea.get(), {mentions: true, emoji: true}); let dz; const $dropzone = $editContentZone.find('.dropzone'); diff --git a/web_src/js/features/repo-migration.js b/web_src/js/features/repo-migration.js new file mode 100644 index 0000000000..6e59d65f32 --- /dev/null +++ b/web_src/js/features/repo-migration.js @@ -0,0 +1,60 @@ +const $service = $('#service_type'); +const $user = $('#auth_username'); +const $pass = $('#auth_password'); +const $token = $('#auth_token'); +const $mirror = $('#mirror'); +const $lfs = $('#lfs'); +const $lfsSettings = $('#lfs_settings'); +const $lfsEndpoint = $('#lfs_endpoint'); +const $items = $('#migrate_items').find('input[type=checkbox]'); + +export default function initRepoMigration() { + checkAuth(); + setLFSSettingsVisibility(); + + $user.on('keyup', () => {checkItems(false)}); + $pass.on('keyup', () => {checkItems(false)}); + $token.on('keyup', () => {checkItems(true)}); + $mirror.on('change', () => {checkItems(true)}); + $('#lfs_settings_show').on('click', () => { $lfsEndpoint.show(); return false }); + $lfs.on('change', setLFSSettingsVisibility); + + const $cloneAddr = $('#clone_addr'); + $cloneAddr.on('change', () => { + const $repoName = $('#repo_name'); + if ($cloneAddr.val().length > 0 && $repoName.val().length === 0) { // Only modify if repo_name input is blank + $repoName.val($cloneAddr.val().match(/^(.*\/)?((.+?)(\.git)?)$/)[3]); + } + }); +} + +function checkAuth() { + const serviceType = $service.val(); + + checkItems(serviceType !== 1); +} + +function checkItems(tokenAuth) { + let enableItems; + if (tokenAuth) { + enableItems = $token.val() !== ''; + } else { + enableItems = $user.val() !== '' || $pass.val() !== ''; + } + if (enableItems && $service.val() > 1) { + if ($mirror.is(':checked')) { + $items.not('[name="wiki"]').attr('disabled', true); + $items.filter('[name="wiki"]').attr('disabled', false); + return; + } + $items.attr('disabled', false); + } else { + $items.attr('disabled', true); + } +} + +function setLFSSettingsVisibility() { + const visible = $lfs.is(':checked'); + $lfsSettings.toggle(visible); + $lfsEndpoint.hide(); +} diff --git a/web_src/js/features/repo-projects.js b/web_src/js/features/repo-projects.js new file mode 100644 index 0000000000..995b971be5 --- /dev/null +++ b/web_src/js/features/repo-projects.js @@ -0,0 +1,194 @@ +const {csrfToken} = window.config; + +async function initRepoProjectSortable() { + const {Sortable} = await import(/* webpackChunkName: "sortable" */'sortablejs'); + const boardColumns = document.getElementsByClassName('board-column'); + + new Sortable( + document.getElementsByClassName('board')[0], + { + group: 'board-column', + draggable: '.board-column', + animation: 150, + ghostClass: 'card-ghost', + onSort: () => { + const board = document.getElementsByClassName('board')[0]; + const boardColumns = board.getElementsByClassName('board-column'); + + boardColumns.forEach((column, i) => { + if (parseInt($(column).data('sorting')) !== i) { + $.ajax({ + url: $(column).data('url'), + data: JSON.stringify({sorting: i, color: rgbToHex($(column).css('backgroundColor'))}), + headers: { + 'X-Csrf-Token': csrfToken, + 'X-Remote': true, + }, + contentType: 'application/json', + method: 'PUT', + }); + } + }); + }, + }, + ); + + for (const column of boardColumns) { + new Sortable( + column.getElementsByClassName('board')[0], + { + group: 'shared', + animation: 150, + ghostClass: 'card-ghost', + onAdd: (e) => { + $.ajax(`${e.to.dataset.url}/${e.item.dataset.issue}`, { + headers: { + 'X-Csrf-Token': csrfToken, + 'X-Remote': true, + }, + contentType: 'application/json', + type: 'POST', + error: () => { + e.from.insertBefore(e.item, e.from.children[e.oldIndex]); + }, + }); + }, + }, + ); + } +} + +export default function initRepoProject() { + if (!$('.repository.projects').length) { + return; + } + + (async () => { + await initRepoProjectSortable(); + })(); + + $('.edit-project-board').each(function () { + const projectHeader = $(this).closest('.board-column-header'); + const projectTitleLabel = projectHeader.find('.board-label'); + const projectTitleInput = $(this).find( + '.content > .form > .field > .project-board-title', + ); + const projectColorInput = $(this).find('.content > .form > .field #new_board_color'); + const boardColumn = $(this).closest('.board-column'); + + if (boardColumn.css('backgroundColor')) { + setLabelColor(projectHeader, rgbToHex(boardColumn.css('backgroundColor'))); + } + + $(this) + .find('.content > .form > .actions > .red') + .on('click', function (e) { + e.preventDefault(); + + $.ajax({ + url: $(this).data('url'), + data: JSON.stringify({title: projectTitleInput.val(), color: projectColorInput.val()}), + headers: { + 'X-Csrf-Token': csrfToken, + 'X-Remote': true, + }, + contentType: 'application/json', + method: 'PUT', + }).done(() => { + projectTitleLabel.text(projectTitleInput.val()); + projectTitleInput.closest('form').removeClass('dirty'); + if (projectColorInput.val()) { + setLabelColor(projectHeader, projectColorInput.val()); + } + boardColumn.attr('style', `background: ${projectColorInput.val()}!important`); + $('.ui.modal').modal('hide'); + }); + }); + }); + + $(document).on('click', '.set-default-project-board', async function (e) { + e.preventDefault(); + + await $.ajax({ + method: 'POST', + url: $(this).data('url'), + headers: { + 'X-Csrf-Token': csrfToken, + 'X-Remote': true, + }, + contentType: 'application/json', + }); + + window.location.reload(); + }); + + $('.delete-project-board').each(function () { + $(this).click(function (e) { + e.preventDefault(); + + $.ajax({ + url: $(this).data('url'), + headers: { + 'X-Csrf-Token': csrfToken, + 'X-Remote': true, + }, + contentType: 'application/json', + method: 'DELETE', + }).done(() => { + window.location.reload(); + }); + }); + }); + + $('#new_board_submit').click(function (e) { + e.preventDefault(); + + const boardTitle = $('#new_board'); + const projectColorInput = $('#new_board_color_picker'); + + $.ajax({ + url: $(this).data('url'), + data: JSON.stringify({title: boardTitle.val(), color: projectColorInput.val()}), + headers: { + 'X-Csrf-Token': csrfToken, + 'X-Remote': true, + }, + contentType: 'application/json', + method: 'POST', + }).done(() => { + boardTitle.closest('form').removeClass('dirty'); + window.location.reload(); + }); + }); +} + +function setLabelColor(label, color) { + const red = getRelativeColor(parseInt(color.substr(1, 2), 16)); + const green = getRelativeColor(parseInt(color.substr(3, 2), 16)); + const blue = getRelativeColor(parseInt(color.substr(5, 2), 16)); + const luminance = 0.2126 * red + 0.7152 * green + 0.0722 * blue; + + if (luminance > 0.179) { + label.removeClass('light-label').addClass('dark-label'); + } else { + label.removeClass('dark-label').addClass('light-label'); + } +} + +/** + * Inspired by W3C recommandation https://www.w3.org/TR/WCAG20/#relativeluminancedef + */ +function getRelativeColor(color) { + color /= 255; + return color <= 0.03928 ? color / 12.92 : ((color + 0.055) / 1.055) ** 2.4; +} + +function rgbToHex(rgb) { + rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); + return `#${hex(rgb[1])}${hex(rgb[2])}${hex(rgb[3])}`; +} + +function hex(x) { + const hexDigits = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']; + return Number.isNaN(x) ? '00' : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16]; +} diff --git a/web_src/js/features/repo-settings.js b/web_src/js/features/repo-settings.js index bd42bcb441..b0d43bd487 100644 --- a/web_src/js/features/repo-settings.js +++ b/web_src/js/features/repo-settings.js @@ -40,10 +40,10 @@ export function initRepoSettingSearchTeamBox() { } -export async function initRepoSettingGitHook() { +export function initRepoSettingGitHook() { if ($('.edit.githook').length === 0) return; const filename = document.querySelector('.hook-filename').textContent; - await createMonaco($('#content')[0], filename, {language: 'shell'}); + const _promise = createMonaco($('#content')[0], filename, {language: 'shell'}); } export function initRepoSettingBranches() { diff --git a/web_src/js/features/stopwatch.js b/web_src/js/features/stopwatch.js index 8364569892..ff3edaf8cc 100644 --- a/web_src/js/features/stopwatch.js +++ b/web_src/js/features/stopwatch.js @@ -3,7 +3,7 @@ const {appSubUrl, csrfToken, notificationSettings, enableTimeTracking} = window. let updateTimeInterval = null; // holds setInterval id when active -export async function initStopwatch() { +export function initStopwatch() { if (!enableTimeTracking) { return; } @@ -135,7 +135,7 @@ async function updateStopwatchData(data) { $('.stopwatch-cancel').attr('action', `${issueUrl}/times/stopwatch/cancel`); $('.stopwatch-issue').text(`${repo_owner_name}/${repo_name}#${issue_index}`); $('.stopwatch-time').text(prettyMilliseconds(seconds * 1000)); - updateStopwatchTime(seconds); + await updateStopwatchTime(seconds); btnEl.removeClass('hidden'); } diff --git a/web_src/js/index.js b/web_src/js/index.js index a3bd35175e..957a0d9e8a 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -7,27 +7,25 @@ import {initDashboardRepoList} from './components/DashboardRepoList.js'; import attachTribute from './features/tribute.js'; import initGlobalCopyToClipboardListener from './features/clipboard.js'; import initContextPopups from './features/contextpopup.js'; -import initGitGraph from './features/gitgraph.js'; +import initRepoGraphGit from './features/repo-graph.js'; import initHeatmap from './features/heatmap.js'; import initImageDiff from './features/imagediff.js'; -import initMigration from './features/migration.js'; -import initProject from './features/projects.js'; +import initRepoMigration from './features/repo-migration.js'; +import initRepoProject from './features/repo-projects.js'; import initServiceWorker from './features/serviceworker.js'; import initTableSort from './features/tablesort.js'; import {initAdminUserListSearchForm} from './features/admin-users.js'; import {initMarkupAnchors} from './markup/anchors.js'; import {initNotificationCount, initNotificationsTable} from './features/notification.js'; -import {initLastCommitLoader} from './features/lastcommitloader.js'; -import {initIssueContentHistory} from './features/issue-content-history.js'; +import {initRepoIssueContentHistory} from './features/repo-issue-content.js'; import {initStopwatch} from './features/stopwatch.js'; -import {initDiffShowMore} from './features/diff.js'; import {initCommentContent, initMarkupContent} from './markup/content.js'; import {initUserAuthLinkAccountView, initUserAuthOauth2} from './features/user-auth.js'; import { initRepoDiffConversationForm, initRepoDiffFileViewToggle, - initRepoDiffReviewButton, + initRepoDiffReviewButton, initRepoDiffShowMore, } from './features/repo-diff.js'; import { initRepoIssueDue, @@ -38,7 +36,7 @@ import { initRepoPullRequestMergeInstruction, initRepoPullRequestReview, } from './features/repo-issue.js'; -import {initRepoCommitButton} from './features/repo-commit.js'; +import {initRepoCommitButton, initRepoCommitLastCommitLoader} from './features/repo-commit.js'; import { initFootLanguageMenu, initGlobalButtonClickOnEnter, @@ -68,9 +66,9 @@ import {initOrgTeamSearchRepoBox, initOrgTeamSettings} from './features/org-team import {initUserAuthU2fAuth, initUserAuthU2fRegister} from './features/user-auth-u2f.js'; import {initRepoRelease, initRepoReleaseEditor} from './features/repo-release.js'; import {initRepoEditor} from './features/repo-editor.js'; -import {initSearchUserBox} from './features/comp/SearchUserBox.js'; +import {initCompSearchUserBox} from './features/comp/SearchUserBox.js'; import {initInstall} from './features/install.js'; -import {initWebHookEditor} from './features/comp/WebHookEditor.js'; +import {initCompWebHookEditor} from './features/comp/WebHookEditor.js'; import {initCommonIssue} from './features/common-issue.js'; import {initRepoBranchButton} from './features/repo-branch.js'; import {initCommonOrganization} from './features/common-organization.js'; @@ -82,85 +80,90 @@ $.fn.tab.settings.silent = true; initVueEnv(); -$(document).ready(async () => { +$(document).ready(() => { initGlobalCommon(); + + initGlobalButtonClickOnEnter(); + initGlobalButtons(); + initGlobalCopyToClipboardListener(); initGlobalDropzone(); + initGlobalEnterQuickSubmit(); + initGlobalFormDirtyLeaveConfirm(); initGlobalLinkActions(); - initGlobalButtons(); - initRepoBranchButton(); + + attachTribute(document.querySelectorAll('#content, .emoji-input')); initCommonIssue(); + initCommonOrganization(); - initSearchUserBox(); - initRepoSettingSearchTeamBox(); - initOrgTeamSearchRepoBox(); + initCompSearchUserBox(); + initCompWebHookEditor(); - initGlobalButtonClickOnEnter(); - initMarkupAnchors(); - initCommentContent(); - initRepoCommentForm(); initInstall(); - initRepoArchiveLinks(); - initRepository(); - initMigration(); - initRepoWikiForm(); - initRepoEditor(); - initCommonOrganization(); - initWebHookEditor(); + + initHeadNavbarContentToggle(); + initFootLanguageMenu(); + + initCommentContent(); + initContextPopups(); + initHeatmap(); + initImageDiff(); + initMarkupAnchors(); + initMarkupContent(); + initServiceWorker(); + initSshKeyFormParser(); + initStopwatch(); + initTableSort(); + initAdminCommon(); - initRepoCodeView(); - initRepoActivityTopAuthorsChart(); + initAdminEmails(); + initAdminUserListSearchForm(); + initDashboardRepoList(); + + initNotificationCount(); + initNotificationsTable(); + + initOrgTeamSearchRepoBox(); initOrgTeamSettings(); - initGlobalEnterQuickSubmit(); - initHeadNavbarContentToggle(); - initFootLanguageMenu(); - initRepoTopicBar(); - initUserAuthU2fAuth(); - initUserAuthU2fRegister(); + + initRepoActivityTopAuthorsChart(); + initRepoArchiveLinks(); + initRepoBranchButton(); + initRepoCodeView(); + initRepoCommentForm(); + initRepoCommitButton(); + initRepoCommitLastCommitLoader(); + initRepoDiffConversationForm(); + initRepoDiffFileViewToggle(); + initRepoDiffReviewButton(); + initRepoDiffShowMore(); + initRepoEditor(); + initRepoGraphGit(); + initRepoIssueContentHistory(); + initRepoIssueDue(); initRepoIssueList(); + initRepoIssueReferenceRepositorySearch(); initRepoIssueTimeTracking(); - initRepoIssueDue(); initRepoIssueWipTitle(); - initRepoPullRequestReview(); + initRepoMigration(); initRepoMigrationStatusChecker(); - initRepoTemplateSearch(); - initRepoIssueReferenceRepositorySearch(); - initContextPopups(); - initTableSort(); - initNotificationsTable(); - initLastCommitLoader(); + initRepoProject(); initRepoPullRequestMergeInstruction(); - initRepoDiffFileViewToggle(); - initRepoReleaseEditor(); + initRepoPullRequestReview(); initRepoRelease(); - initDiffShowMore(); - initIssueContentHistory(); - initAdminUserListSearchForm(); - initGlobalCopyToClipboardListener(); - initUserAuthOauth2(); - initRepoDiffReviewButton(); - initRepoCommitButton(); - initAdminEmails(); - initGlobalEnterQuickSubmit(); - initSshKeyFormParser(); - initGlobalFormDirtyLeaveConfirm(); - initUserSettings(); + initRepoReleaseEditor(); + initRepoSettingGitHook(); + initRepoSettingSearchTeamBox(); initRepoSettingsCollaboration(); - initUserAuthLinkAccountView(); - initRepoDiffConversationForm(); + initRepoTemplateSearch(); + initRepoTopicBar(); + initRepoWikiForm(); + initRepository(); - // parallel init of async loaded features - await Promise.all([ - attachTribute(document.querySelectorAll('#content, .emoji-input')), - initGitGraph(), - initHeatmap(), - initProject(), - initServiceWorker(), - initNotificationCount(), - initStopwatch(), - initMarkupContent(), - initRepoSettingGitHook(), - initImageDiff(), - ]); + initUserAuthLinkAccountView(); + initUserAuthOauth2(); + initUserAuthU2fAuth(); + initUserAuthU2fRegister(); + initUserSettings(); }); diff --git a/web_src/js/markup/content.js b/web_src/js/markup/content.js index 19b749aaab..0564199bbf 100644 --- a/web_src/js/markup/content.js +++ b/web_src/js/markup/content.js @@ -2,8 +2,8 @@ import {renderMermaid} from './mermaid.js'; import {initMarkupTasklist} from './tasklist.js'; // code that runs for all markup content -export async function initMarkupContent() { - await renderMermaid(document.querySelectorAll('code.language-mermaid')); +export function initMarkupContent() { + const _promise = renderMermaid(document.querySelectorAll('code.language-mermaid')); } // code that only runs for comments -- cgit v1.2.3