forgejo/web_src/js/features/pull-view-file.js
charles afc21e6aa7
Fix counter display number incorrectly displayed on the page (#29448)
issue : #28239

The counter number script uses the 'checkbox' attribute to determine
whether an item is selected or not.

However, the input event only increments the counter value, and when
more items are displayed, it does not update all previously loaded
items.

As a result, the display becomes incorrect because it triggers the
update counter script, but checkboxes that are selected without the
'checked' attribute are not counted

(cherry picked from commit 252047ed2e09e3f1f1ab394cd62995cf4cabe506)
2024-03-06 12:10:44 +08:00

97 lines
4.5 KiB
JavaScript

import {diffTreeStore} from '../modules/stores.js';
import {setFileFolding} from './file-fold.js';
import {POST} from '../modules/fetch.js';
const {pageData} = window.config;
const prReview = pageData.prReview || {};
const viewedStyleClass = 'viewed-file-checked-form';
const viewedCheckboxSelector = '.viewed-file-form'; // Selector under which all "Viewed" checkbox forms can be found
const expandFilesBtnSelector = '#expand-files-btn';
const collapseFilesBtnSelector = '#collapse-files-btn';
// Refreshes the summary of viewed files if present
// The data used will be window.config.pageData.prReview.numberOf{Viewed}Files
function refreshViewedFilesSummary() {
const viewedFilesProgress = document.getElementById('viewed-files-summary');
viewedFilesProgress?.setAttribute('value', prReview.numberOfViewedFiles);
const summaryLabel = document.getElementById('viewed-files-summary-label');
if (summaryLabel) summaryLabel.innerHTML = summaryLabel.getAttribute('data-text-changed-template')
.replace('%[1]d', prReview.numberOfViewedFiles)
.replace('%[2]d', prReview.numberOfFiles);
}
// Explicitly recounts how many files the user has currently reviewed by counting the number of checked "viewed" checkboxes
// Additionally, the viewed files summary will be updated if it exists
export function countAndUpdateViewedFiles() {
// The number of files is constant, but the number of viewed files can change because files can be loaded dynamically
prReview.numberOfViewedFiles = document.querySelectorAll(`${viewedCheckboxSelector} > input[type=checkbox][checked]`).length;
refreshViewedFilesSummary();
}
// Initializes a listener for all children of the given html element
// (for example 'document' in the most basic case)
// to watch for changes of viewed-file checkboxes
export function initViewedCheckboxListenerFor() {
for (const form of document.querySelectorAll(`${viewedCheckboxSelector}:not([data-has-viewed-checkbox-listener="true"])`)) {
// To prevent double addition of listeners
form.setAttribute('data-has-viewed-checkbox-listener', true);
// The checkbox consists of a div containing the real checkbox with its label and the CSRF token,
// hence the actual checkbox first has to be found
const checkbox = form.querySelector('input[type=checkbox]');
checkbox.addEventListener('input', function() {
// Mark the file as viewed visually - will especially change the background
if (this.checked) {
form.classList.add(viewedStyleClass);
checkbox.setAttribute('checked', '');
prReview.numberOfViewedFiles++;
} else {
form.classList.remove(viewedStyleClass);
checkbox.removeAttribute('checked');
prReview.numberOfViewedFiles--;
}
// Update viewed-files summary and remove "has changed" label if present
refreshViewedFilesSummary();
const hasChangedLabel = form.parentNode.querySelector('.changed-since-last-review');
hasChangedLabel?.remove();
const fileName = checkbox.getAttribute('name');
// check if the file is in our difftreestore and if we find it -> change the IsViewed status
const fileInPageData = diffTreeStore().files.find((x) => x.Name === fileName);
if (fileInPageData) {
fileInPageData.IsViewed = this.checked;
}
// Unfortunately, actual forms cause too many problems, hence another approach is needed
const files = {};
files[fileName] = this.checked;
const data = {files};
const headCommitSHA = form.getAttribute('data-headcommit');
if (headCommitSHA) data.headCommitSHA = headCommitSHA;
POST(form.getAttribute('data-link'), {data});
// Fold the file accordingly
const parentBox = form.closest('.diff-file-header');
setFileFolding(parentBox.closest('.file-content'), parentBox.querySelector('.fold-file'), this.checked);
});
}
}
export function initExpandAndCollapseFilesButton() {
// expand btn
document.querySelector(expandFilesBtnSelector)?.addEventListener('click', () => {
for (const box of document.querySelectorAll('.file-content[data-folded="true"]')) {
setFileFolding(box, box.querySelector('.fold-file'), false);
}
});
// collapse btn, need to exclude the div of “show more”
document.querySelector(collapseFilesBtnSelector)?.addEventListener('click', () => {
for (const box of document.querySelectorAll('.file-content:not([data-folded="true"])')) {
if (box.getAttribute('id') === 'diff-incomplete') continue;
setFileFolding(box, box.querySelector('.fold-file'), true);
}
});
}