summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/diff.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/diff.js')
-rw-r--r--app/assets/javascripts/diff.js128
1 files changed, 128 insertions, 0 deletions
diff --git a/app/assets/javascripts/diff.js b/app/assets/javascripts/diff.js
new file mode 100644
index 00000000000..cfa60325fcc
--- /dev/null
+++ b/app/assets/javascripts/diff.js
@@ -0,0 +1,128 @@
+/* eslint-disable class-methods-use-this */
+
+require('./lib/utils/url_utility');
+
+const UNFOLD_COUNT = 20;
+let isBound = false;
+
+class Diff {
+ constructor() {
+ const $diffFile = $('.files .diff-file');
+ $diffFile.singleFileDiff();
+ $diffFile.filesCommentButton();
+
+ $diffFile.each((index, file) => new gl.ImageFile(file));
+
+ if (this.diffViewType() === 'parallel') {
+ $('.content-wrapper .container-fluid').removeClass('container-limited');
+ }
+
+ if (!isBound) {
+ $(document)
+ .on('click', '.js-unfold', this.handleClickUnfold.bind(this))
+ .on('click', '.diff-line-num a', this.handleClickLineNum.bind(this));
+ isBound = true;
+ }
+
+ if (gl.utils.getLocationHash()) {
+ this.highlightSelectedLine();
+ }
+
+ this.openAnchoredDiff();
+ }
+
+ handleClickUnfold(e) {
+ const $target = $(e.target);
+ // current babel config relies on iterators implementation, so we cannot simply do:
+ // const [oldLineNumber, newLineNumber] = this.lineNumbers($target.parent());
+ const ref = this.lineNumbers($target.parent());
+ const oldLineNumber = ref[0];
+ const newLineNumber = ref[1];
+ 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;
+ }
+ }
+
+ const file = $target.parents('.diff-file');
+ const link = file.data('blob-diff-path');
+ const view = file.data('view');
+
+ const params = { since, to, bottom, offset, unfold, view };
+ $.get(link, params, response => $target.parent().replaceWith(response));
+ }
+
+ openAnchoredDiff(cb) {
+ const locationHash = gl.utils.getLocationHash();
+ 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();
+ if (cb) cb();
+ });
+ } 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();
+ }
+
+ diffViewType() {
+ return $('.inline-parallel-buttons a.active').data('view-type');
+ }
+
+ lineNumbers(line) {
+ if (!line.children().length) {
+ return [0, 0];
+ }
+ return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10));
+ }
+
+ highlightSelectedLine() {
+ const hash = gl.utils.getLocationHash();
+ 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');
+ }
+ }
+}
+
+window.gl = window.gl || {};
+window.gl.Diff = Diff;