debian-mirror-gitlab/app/assets/javascripts/diff.js

237 lines
7.2 KiB
JavaScript
Raw Normal View History

2018-05-09 12:01:36 +05:30
import $ from 'jquery';
2022-05-07 20:08:51 +05:30
import { merge } from 'lodash';
2023-05-27 22:25:52 +05:30
import { createAlert } from '~/alert';
2021-03-11 19:13:27 +05:30
import axios from '~/lib/utils/axios_utils';
2018-03-27 19:54:05 +05:30
import { __ } from '~/locale';
2017-09-10 17:25:29 +05:30
import FilesCommentButton from './files_comment_button';
2019-12-04 20:38:33 +05:30
import initImageDiffHelper from './image_diff/helpers/init_image_diff';
2021-03-11 19:13:27 +05:30
import { getLocationHash } from './lib/utils/url_utility';
import SingleFileDiff from './single_file_diff';
2016-09-13 17:45:13 +05:30
2017-08-17 22:00:37 +05:30
const UNFOLD_COUNT = 20;
let isBound = false;
2018-03-17 18:26:18 +05:30
export default class Diff {
2023-03-17 16:20:25 +05:30
constructor({ mergeRequestEventHub } = {}) {
2017-08-17 22:00:37 +05:30
const $diffFile = $('.files .diff-file');
2017-09-10 17:25:29 +05:30
2023-03-17 16:20:25 +05:30
if (mergeRequestEventHub) {
this.mrHub = mergeRequestEventHub;
}
2017-09-10 17:25:29 +05:30
$diffFile.each((index, file) => {
if (!$.data(file, 'singleFileDiff')) {
$.data(file, 'singleFileDiff', new SingleFileDiff(file));
}
});
2018-03-17 18:26:18 +05:30
const tab = document.getElementById('diffs');
2018-12-13 13:39:08 +05:30
if (!tab || (tab && tab.dataset && tab.dataset.isLocked !== ''))
FilesCommentButton.init($diffFile);
2017-08-17 22:00:37 +05:30
2021-03-08 18:12:59 +05:30
const firstFile = $('.files').first().get(0);
2022-07-23 23:45:48 +05:30
const canCreateNote =
firstFile && Object.prototype.hasOwnProperty.call(firstFile.dataset, 'canCreateNote');
2019-12-04 20:38:33 +05:30
$diffFile.each((index, file) => initImageDiffHelper.initImageDiff(file, canCreateNote));
2017-08-17 22:00:37 +05:30
if (!isBound) {
$(document)
.on('click', '.js-unfold', this.handleClickUnfold.bind(this))
2018-03-17 18:26:18 +05:30
.on('click', '.diff-line-num a', this.handleClickLineNum.bind(this))
2023-03-17 16:20:25 +05:30
.on('mousedown', 'td.line_content.parallel', this.handleParallelLineDown.bind(this))
.on('click', '.inline-parallel-buttons a', ($e) => this.viewTypeSwitch($e));
2017-08-17 22:00:37 +05:30
isBound = true;
2016-09-13 17:45:13 +05:30
}
2018-03-17 18:26:18 +05:30
if (getLocationHash()) {
2017-08-17 22:00:37 +05:30
this.highlightSelectedLine();
2016-11-03 12:29:30 +05:30
}
2017-08-17 22:00:37 +05:30
this.openAnchoredDiff();
2022-05-07 20:08:51 +05:30
this.prepareRenderedDiff();
2017-08-17 22:00:37 +05:30
}
handleClickUnfold(e) {
const $target = $(e.target);
const [oldLineNumber, newLineNumber] = this.lineNumbers($target.parent());
const offset = newLineNumber - oldLineNumber;
const bottom = $target.hasClass('js-unfold-bottom');
let since;
let to;
let unfold = true;
if (bottom) {
const lineNumber = newLineNumber + 1;
since = lineNumber;
to = lineNumber + UNFOLD_COUNT;
} else {
const lineNumber = newLineNumber - 1;
since = lineNumber - UNFOLD_COUNT;
to = lineNumber;
// make sure we aren't loading more than we need
const prevNewLine = this.lineNumbers($target.parent().prev())[1];
if (since <= prevNewLine + 1) {
since = prevNewLine + 1;
unfold = false;
2016-09-13 17:45:13 +05:30
}
2017-08-17 22:00:37 +05:30
}
const file = $target.parents('.diff-file');
2018-03-27 19:54:05 +05:30
const link = file.data('blobDiffPath');
2017-08-17 22:00:37 +05:30
const view = file.data('view');
const params = { since, to, bottom, offset, unfold, view };
2018-12-13 13:39:08 +05:30
axios
.get(link, { params })
.then(({ data }) => $target.parent().replaceWith(data))
2021-09-30 23:02:18 +05:30
.catch(() =>
2022-11-25 23:54:43 +05:30
createAlert({
2021-09-30 23:02:18 +05:30
message: __('An error occurred while loading diff'),
}),
);
2017-08-17 22:00:37 +05:30
}
2016-09-13 17:45:13 +05:30
2017-08-17 22:00:37 +05:30
openAnchoredDiff(cb) {
2018-03-17 18:26:18 +05:30
const locationHash = getLocationHash();
2017-08-17 22:00:37 +05:30
const anchoredDiff = locationHash && locationHash.split('_')[0];
if (!anchoredDiff) return;
const diffTitle = $(`#${anchoredDiff}`);
const diffFile = diffTitle.closest('.diff-file');
const nothingHereBlock = $('.nothing-here-block:visible', diffFile);
if (nothingHereBlock.length) {
const clickTarget = $('.js-file-title, .click-to-expand', diffFile);
diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => {
this.highlightSelectedLine();
2022-08-13 15:12:31 +05:30
this.prepareRenderedDiff();
2017-08-17 22:00:37 +05:30
if (cb) cb();
2016-09-13 17:45:13 +05:30
});
2017-08-17 22:00:37 +05:30
} else if (cb) {
cb();
}
}
handleClickLineNum(e) {
const hash = $(e.currentTarget).attr('href');
e.preventDefault();
if (window.history.pushState) {
window.history.pushState(null, null, hash);
} else {
window.location.hash = hash;
}
this.highlightSelectedLine();
}
2018-03-17 18:26:18 +05:30
// eslint-disable-next-line class-methods-use-this
handleParallelLineDown(e) {
const line = $(e.currentTarget);
const table = line.closest('table');
table.removeClass('left-side-selected right-side-selected');
2016-09-13 17:45:13 +05:30
2021-03-08 18:12:59 +05:30
const lineClass = ['left-side', 'right-side'].filter((name) => line.hasClass(name))[0];
2018-03-17 18:26:18 +05:30
if (lineClass) {
table.addClass(`${lineClass}-selected`);
}
}
// eslint-disable-next-line class-methods-use-this
2017-08-17 22:00:37 +05:30
diffViewType() {
2018-03-27 19:54:05 +05:30
return $('.inline-parallel-buttons a.active').data('viewType');
2017-08-17 22:00:37 +05:30
}
2023-03-17 16:20:25 +05:30
viewTypeSwitch(event) {
const click = event.originalEvent;
const diffSource = new URL(click.target.getAttribute('href'), document.location.href);
if (this.mrHub) {
click.preventDefault();
click.stopPropagation();
diffSource.pathname = `${diffSource.pathname}.json`;
this.mrHub.$emit('diff:switch-view-type', { source: diffSource.toString() });
}
}
2018-03-17 18:26:18 +05:30
// eslint-disable-next-line class-methods-use-this
2017-08-17 22:00:37 +05:30
lineNumbers(line) {
const children = line.find('.diff-line-num').toArray();
if (children.length !== 2) {
return [0, 0];
}
2021-03-08 18:12:59 +05:30
return children.map((elm) => parseInt($(elm).data('linenumber'), 10) || 0);
2017-08-17 22:00:37 +05:30
}
2018-03-17 18:26:18 +05:30
// eslint-disable-next-line class-methods-use-this
2017-08-17 22:00:37 +05:30
highlightSelectedLine() {
2018-03-17 18:26:18 +05:30
const hash = getLocationHash();
2017-08-17 22:00:37 +05:30
const $diffFiles = $('.diff-file');
$diffFiles.find('.hll').removeClass('hll');
if (hash) {
$diffFiles
.find(`tr#${hash}:not(.match) td, td#${hash}, td[data-line-code="${hash}"]`)
.addClass('hll');
}
}
2022-05-07 20:08:51 +05:30
prepareRenderedDiff() {
2022-08-13 15:12:31 +05:30
const allElements = this.elementsForRenderedDiff();
2022-05-07 20:08:51 +05:30
const diff = this;
2022-08-13 15:12:31 +05:30
for (const [fileHash, fileElements] of Object.entries(allElements)) {
// eslint-disable no-param-reassign
fileElements.rawButton.onclick = () => {
diff.showRawViewer(fileHash, diff.elementsForRenderedDiff()[fileHash]);
};
2022-05-07 20:08:51 +05:30
2022-08-13 15:12:31 +05:30
fileElements.renderedButton.onclick = () => {
diff.showRenderedViewer(fileHash, diff.elementsForRenderedDiff()[fileHash]);
};
// eslint-enable no-param-reassign
2022-05-07 20:08:51 +05:30
2022-08-13 15:12:31 +05:30
diff.showRenderedViewer(fileHash, fileElements);
}
2022-05-07 20:08:51 +05:30
}
2022-08-27 11:52:29 +05:30
// eslint-disable-next-line class-methods-use-this
2022-05-07 20:08:51 +05:30
formatElementToObject = (element) => {
const key = element.attributes['data-file-hash'].value;
const name = element.attributes['data-diff-toggle-entity'].value;
return { [key]: { [name]: element } };
};
2022-08-13 15:12:31 +05:30
elementsForRenderedDiff = () => {
const $elements = $('[data-diff-toggle-entity]');
if ($elements.length === 0) return {};
2022-05-07 20:08:51 +05:30
2022-08-13 15:12:31 +05:30
const diff = this;
return $elements.toArray().map(diff.formatElementToObject).reduce(merge);
};
2022-08-27 11:52:29 +05:30
// eslint-disable-next-line class-methods-use-this
2022-08-13 15:12:31 +05:30
showRawViewer = (fileHash, elements) => {
if (elements === undefined) return;
elements.rawButton.classList.add('selected');
elements.renderedButton.classList.remove('selected');
elements.renderedViewer.classList.add('hidden');
elements.rawViewer.classList.remove('hidden');
};
2022-08-27 11:52:29 +05:30
// eslint-disable-next-line class-methods-use-this
2022-08-13 15:12:31 +05:30
showRenderedViewer = (fileHash, elements) => {
if (elements === undefined) return;
2022-05-07 20:08:51 +05:30
2022-08-13 15:12:31 +05:30
elements.rawButton.classList.remove('selected');
elements.rawViewer.classList.add('hidden');
2022-05-07 20:08:51 +05:30
2022-08-13 15:12:31 +05:30
elements.renderedButton.classList.add('selected');
elements.renderedViewer.classList.remove('hidden');
2022-05-07 20:08:51 +05:30
};
2017-08-17 22:00:37 +05:30
}