summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/diff.js
blob: cfa60325fccb60dfbeaf431f629098497caa22c2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
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;