mirror of
https://github.com/gitbucket/gitbucket.git
synced 2025-11-03 20:15:59 +01:00
Links to files and lines in the diff view (#2685)
This commit is contained in:
@@ -10,6 +10,7 @@ import gitbucket.core.plugin.{PluginRegistry, RenderRequest}
|
|||||||
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
import gitbucket.core.service.RepositoryService.RepositoryInfo
|
||||||
import gitbucket.core.service.{RepositoryService, RequestCache}
|
import gitbucket.core.service.{RepositoryService, RequestCache}
|
||||||
import gitbucket.core.util.{FileUtil, JGitUtil, StringUtil}
|
import gitbucket.core.util.{FileUtil, JGitUtil, StringUtil}
|
||||||
|
import org.apache.commons.codec.digest.DigestUtils
|
||||||
import play.twirl.api.{Html, HtmlFormat}
|
import play.twirl.api.{Html, HtmlFormat}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -506,4 +507,6 @@ object helpers extends AvatarImageProvider with LinkConverter with RequestCache
|
|||||||
s"$baseUrl${if (baseUrl.contains("?")) "&" else "?"}$queryString"
|
s"$baseUrl${if (baseUrl.contains("?")) "&" else "?"}$queryString"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def md5(value: String): String = DigestUtils.md5Hex(value)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,11 @@
|
|||||||
showLineNotes: Boolean)(implicit context: gitbucket.core.controller.Context)
|
showLineNotes: Boolean)(implicit context: gitbucket.core.controller.Context)
|
||||||
@import gitbucket.core.view.helpers
|
@import gitbucket.core.view.helpers
|
||||||
@import org.eclipse.jgit.diff.DiffEntry.ChangeType
|
@import org.eclipse.jgit.diff.DiffEntry.ChangeType
|
||||||
|
<style>
|
||||||
|
th.line-num {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@if(showIndex){
|
@if(showIndex){
|
||||||
<div class="pull-right" style="margin-bottom: 10px;">
|
<div class="pull-right" style="margin-bottom: 10px;">
|
||||||
@if(oldCommitId.isEmpty && newCommitId.isDefined) {
|
@if(oldCommitId.isEmpty && newCommitId.isDefined) {
|
||||||
@@ -59,7 +64,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<span class="diffstat"><i class="octicon octicon-diff-renamed"></i></span>
|
<span class="diffstat"><i class="octicon octicon-diff-renamed"></i></span>
|
||||||
<span class="monospace">@diff.oldPath → @diff.newPath</span>
|
<a href="#diff-@helpers.md5(diff.newPath)" id="diff-@helpers.md5(diff.newPath)" class="file-hash"><span class="strong">@diff.oldPath → @diff.newPath</span></a>
|
||||||
}
|
}
|
||||||
@if(diff.changeType == ChangeType.ADD || diff.changeType == ChangeType.MODIFY){
|
@if(diff.changeType == ChangeType.ADD || diff.changeType == ChangeType.MODIFY){
|
||||||
@if(newCommitId.isDefined){
|
@if(newCommitId.isDefined){
|
||||||
@@ -76,7 +81,7 @@
|
|||||||
<i class="octicon octicon-diff-modified"></i>
|
<i class="octicon octicon-diff-modified"></i>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
<span class="monospace">@diff.newPath</span>
|
<a href="#diff-@helpers.md5(diff.newPath)" id="diff-@helpers.md5(diff.newPath)" class="file-hash"><span class="strong">@diff.newPath</span></a>
|
||||||
}
|
}
|
||||||
@if(diff.changeType == ChangeType.DELETE){
|
@if(diff.changeType == ChangeType.DELETE){
|
||||||
@if(oldCommitId.isDefined){
|
@if(oldCommitId.isDefined){
|
||||||
@@ -86,7 +91,7 @@
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<span class="diffstat"><i class="octicon octicon-diff-removed"></i></span>
|
<span class="diffstat"><i class="octicon octicon-diff-removed"></i></span>
|
||||||
<span class="monospace">@diff.oldPath</span>
|
<a href="#diff-@helpers.md5(diff.oldPath)" id="diff-@helpers.md5(diff.oldPath)" class="file-hash"><span class="strong">@diff.oldPath</span></a>
|
||||||
}
|
}
|
||||||
@if(diff.oldMode != diff.newMode){
|
@if(diff.oldMode != diff.newMode){
|
||||||
<span class="monospace">@diff.oldMode → @diff.newMode</span>
|
<span class="monospace">@diff.oldMode → @diff.newMode</span>
|
||||||
@@ -180,6 +185,10 @@ $(function(){
|
|||||||
}
|
}
|
||||||
renderDiffs();
|
renderDiffs();
|
||||||
|
|
||||||
|
window.onhashchange = function(){
|
||||||
|
updateHighlighting();
|
||||||
|
}
|
||||||
|
|
||||||
$('.toggle-notes').change(function() {
|
$('.toggle-notes').change(function() {
|
||||||
if (!$(this).prop('checked')) {
|
if (!$(this).prop('checked')) {
|
||||||
$(this).closest('table').find('.not-diff.inline-comment-form').remove();
|
$(this).closest('table').find('.not-diff.inline-comment-form').remove();
|
||||||
@@ -188,7 +197,7 @@ $(function(){
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('.ignore-whitespace').change(function() {
|
$('.ignore-whitespace').change(function() {
|
||||||
renderOneDiff($(this).closest("table").find(".diffText"), window.viewType);
|
renderOneDiff($(this).closest("table").find(".diffText"), window.viewType, $(this).closest("table").find(".file-hash")[0].id);
|
||||||
});
|
});
|
||||||
|
|
||||||
function getInlineContainer(where) {
|
function getInlineContainer(where) {
|
||||||
@@ -208,7 +217,7 @@ $(function(){
|
|||||||
|
|
||||||
function showCommentForm(commitId, fileName, oldLineNumber, newLineNumber, $tr){
|
function showCommentForm(commitId, fileName, oldLineNumber, newLineNumber, $tr){
|
||||||
// assemble Ajax url
|
// assemble Ajax url
|
||||||
var url = '@helpers.url(repository)/commit/' + commitId + '/comment/_form?fileName=' + fileName@issueId.map { id => + '&issueId=@id' };
|
let url = '@helpers.url(repository)/commit/' + commitId + '/comment/_form?fileName=' + fileName@issueId.map { id => + '&issueId=@id' };
|
||||||
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
||||||
url += ('&oldLineNumber=' + oldLineNumber)
|
url += ('&oldLineNumber=' + oldLineNumber)
|
||||||
}
|
}
|
||||||
@@ -218,7 +227,7 @@ $(function(){
|
|||||||
// send Ajax request
|
// send Ajax request
|
||||||
$.get(url, { dataType : 'html' }, function(responseContent) {
|
$.get(url, { dataType : 'html' }, function(responseContent) {
|
||||||
// create container
|
// create container
|
||||||
var tmp;
|
let tmp;
|
||||||
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
if (!isNaN(oldLineNumber) && oldLineNumber) {
|
||||||
if (!isNaN(newLineNumber) && newLineNumber) {
|
if (!isNaN(newLineNumber) && newLineNumber) {
|
||||||
tmp = getInlineContainer();
|
tmp = getInlineContainer();
|
||||||
@@ -240,16 +249,16 @@ $(function(){
|
|||||||
|
|
||||||
// Add comment button
|
// Add comment button
|
||||||
$('.diff-outside').on('click','table.diff .add-comment',function() {
|
$('.diff-outside').on('click','table.diff .add-comment',function() {
|
||||||
var $this = $(this);
|
const $this = $(this);
|
||||||
var $tr = $this.closest('tr');
|
const $tr = $this.closest('tr');
|
||||||
var $check = $this.closest('table:not(.diff)').find('.toggle-notes');
|
const $check = $this.closest('table:not(.diff)').find('.toggle-notes');
|
||||||
if (!$check.prop('checked')) {
|
if (!$check.prop('checked')) {
|
||||||
$check.prop('checked', true).trigger('change');
|
$check.prop('checked', true).trigger('change');
|
||||||
}
|
}
|
||||||
if (!$tr.nextAll(':not(.not-diff):first').prev().hasClass('inline-comment-form')) {
|
if (!$tr.nextAll(':not(.not-diff):first').prev().hasClass('inline-comment-form')) {
|
||||||
var commitId = $this.closest('.table-bordered').attr('commitId'),
|
const commitId = $this.closest('.table-bordered').attr('commitId'),
|
||||||
fileName = $this.closest('.table-bordered').attr('fileName'),
|
fileName = $this.closest('.table-bordered').attr('fileName');
|
||||||
oldLineNumber, newLineNumber;
|
let oldLineNumber, newLineNumber;
|
||||||
if (window.viewType == 0) {
|
if (window.viewType == 0) {
|
||||||
oldLineNumber = $this.parent().prev('.oldline').attr('line-number');
|
oldLineNumber = $this.parent().prev('.oldline').attr('line-number');
|
||||||
newLineNumber = $this.parent().prev('.newline').attr('line-number');
|
newLineNumber = $this.parent().prev('.newline').attr('line-number');
|
||||||
@@ -268,21 +277,37 @@ $(function(){
|
|||||||
|
|
||||||
// Reply comment
|
// Reply comment
|
||||||
$('.diff-outside').on('click', '.reply-comment',function(){
|
$('.diff-outside').on('click', '.reply-comment',function(){
|
||||||
var $this = $(this);
|
const $this = $(this);
|
||||||
var $tr = $this.closest('tr');
|
const $tr = $this.closest('tr');
|
||||||
var commitId = $this.closest('.table-bordered').attr('commitId');
|
const commitId = $this.closest('.table-bordered').attr('commitId');
|
||||||
var fileName = $this.data('filename');
|
const fileName = $this.data('filename');
|
||||||
var oldLineNumber = $this.data('oldline');
|
const oldLineNumber = $this.data('oldline');
|
||||||
var newLineNumber = $this.data('newline');
|
const newLineNumber = $this.data('newline');
|
||||||
|
|
||||||
showCommentForm(commitId, fileName, oldLineNumber, newLineNumber, $tr);
|
showCommentForm(commitId, fileName, oldLineNumber, newLineNumber, $tr);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Line selection
|
||||||
|
$('.diff-outside').on('click','table.diff th.line-num',function(e) {
|
||||||
|
const $this = $(this);
|
||||||
|
const hash = location.hash;
|
||||||
|
const baseUrl = location.toString().split("#")[0];
|
||||||
|
|
||||||
|
if (e.shiftKey == true && hash.match(/#diff-\w+-L\d+(-L\d+)?/)) {
|
||||||
|
const fragments = hash.split('-');
|
||||||
|
window.history.pushState('', '', baseUrl + '#diff-' + fragments[1] + '-' + fragments[2] + '-' + $this[0].id.split('-')[2]);
|
||||||
|
} else {
|
||||||
|
window.history.pushState('', '', baseUrl + '#' + $this[0].id);
|
||||||
|
}
|
||||||
|
getSelection().empty();
|
||||||
|
updateHighlighting();
|
||||||
|
});
|
||||||
|
|
||||||
function renderOneCommitCommentIntoDiff($v, diff){
|
function renderOneCommitCommentIntoDiff($v, diff){
|
||||||
//var filename = $v.attr('filename');
|
//var filename = $v.attr('filename');
|
||||||
var oldline = $v.attr('oldline');
|
const oldline = $v.attr('oldline');
|
||||||
var newline = $v.attr('newline');
|
const newline = $v.attr('newline');
|
||||||
var tmp;
|
let tmp;
|
||||||
if (typeof oldline !== 'undefined') {
|
if (typeof oldline !== 'undefined') {
|
||||||
if (typeof newline !== 'undefined') {
|
if (typeof newline !== 'undefined') {
|
||||||
tmp = getInlineContainer();
|
tmp = getInlineContainer();
|
||||||
@@ -312,8 +337,8 @@ $(function(){
|
|||||||
}
|
}
|
||||||
del = 5 - add;
|
del = 5 - add;
|
||||||
}
|
}
|
||||||
var ret = $('<div class="diffstat-bar">');
|
const ret = $('<div class="diffstat-bar">');
|
||||||
for(var i = 0; i < 5; i++){
|
for(let i = 0; i < 5; i++){
|
||||||
if(add){
|
if(add){
|
||||||
ret.append('<span class="text-diff-added">■</span>');
|
ret.append('<span class="text-diff-added">■</span>');
|
||||||
add--;
|
add--;
|
||||||
@@ -327,13 +352,13 @@ $(function(){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderOneDiff(diffText, viewType){
|
function renderOneDiff(diffText, viewType, fileHash){
|
||||||
var table = diffText.closest("table[data-diff-id]");
|
const table = diffText.closest("table[data-diff-id]");
|
||||||
var i = table.data("diff-id");
|
const i = table.data("diff-id");
|
||||||
var ignoreWhiteSpace = table.find('.ignore-whitespace').prop('checked');
|
const ignoreWhiteSpace = table.find('.ignore-whitespace').prop('checked');
|
||||||
diffUsingJS('oldText-' + i, 'newText-' + i, diffText.attr('id'), viewType, ignoreWhiteSpace);
|
diffUsingJS('oldText-' + i, 'newText-' + i, diffText.attr('id'), viewType, ignoreWhiteSpace, fileHash);
|
||||||
var add = diffText.find("table").attr("add") * 1;
|
const add = diffText.find("table").attr("add") * 1;
|
||||||
var del = diffText.find("table").attr("del") * 1;
|
const del = diffText.find("table").attr("del") * 1;
|
||||||
table.find(".diffstat").text(add + del + " ").append(renderStatBar(add, del)).attr("title", add + " additions & " + del + " deletions").tooltip();
|
table.find(".diffstat").text(add + del + " ").append(renderStatBar(add, del)).attr("title", add + " additions & " + del + " deletions").tooltip();
|
||||||
$('span.diffstat[data-diff-id="' + i + '"]')
|
$('span.diffstat[data-diff-id="' + i + '"]')
|
||||||
.html('<span class="text-diff-added">+' + add + '</span><span class="text-diff-deleted">-' + del + '</span>')
|
.html('<span class="text-diff-added">+' + add + '</span><span class="text-diff-deleted">-' + del + '</span>')
|
||||||
@@ -347,7 +372,7 @@ $(function(){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
@if(showLineNotes){
|
@if(showLineNotes){
|
||||||
var fileName = table.attr('filename');
|
const fileName = table.attr('filename');
|
||||||
$('.inline-comment').each(function(i, v) {
|
$('.inline-comment').each(function(i, v) {
|
||||||
if($(this).attr('filename') == fileName){
|
if($(this).attr('filename') == fileName){
|
||||||
renderOneCommitCommentIntoDiff($(this), table);
|
renderOneCommitCommentIntoDiff($(this), table);
|
||||||
@@ -358,13 +383,13 @@ $(function(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderReplyComment($table){
|
function renderReplyComment($table){
|
||||||
var elements = {};
|
const elements = {};
|
||||||
var filename, newline, oldline;
|
let filename, newline, oldline;
|
||||||
$table.find('.comment-box-container .inline-comment').each(function(i, e){
|
$table.find('.comment-box-container .inline-comment').each(function(i, e){
|
||||||
filename = $(e).attr('filename');
|
filename = $(e).attr('filename');
|
||||||
newline = $(e).attr('newline');
|
newline = $(e).attr('newline');
|
||||||
oldline = $(e).attr('oldline');
|
oldline = $(e).attr('oldline');
|
||||||
var key = filename + '-' + newline + '-' + oldline;
|
const key = filename + '-' + newline + '-' + oldline;
|
||||||
elements[key] = {
|
elements[key] = {
|
||||||
element: $(e),
|
element: $(e),
|
||||||
filename: filename,
|
filename: filename,
|
||||||
@@ -372,18 +397,18 @@ $(function(){
|
|||||||
oldline: oldline
|
oldline: oldline
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
for(var key in elements){
|
for(const key in elements){
|
||||||
filename = elements[key]['filename'];
|
filename = elements[key]['filename'];
|
||||||
oldline = elements[key]['oldline']; //? elements[key]['oldline'] : '';
|
oldline = elements[key]['oldline']; //? elements[key]['oldline'] : '';
|
||||||
newline = elements[key]['newline']; //? elements[key]['newline'] : '';
|
newline = elements[key]['newline']; //? elements[key]['newline'] : '';
|
||||||
|
|
||||||
var $v = $('<div class="commit-comment-box reply-comment-box">')
|
const $v = $('<div class="commit-comment-box reply-comment-box">')
|
||||||
.append($('<input type="text" class="form-control reply-comment" placeholder="Reply..." '
|
.append($('<input type="text" class="form-control reply-comment" placeholder="Reply..." '
|
||||||
+ 'data-filename="' + filename + '" '
|
+ 'data-filename="' + filename + '" '
|
||||||
+ 'data-newline="' + newline + '" '
|
+ 'data-newline="' + newline + '" '
|
||||||
+ 'data-oldline="' + oldline + '">'));
|
+ 'data-oldline="' + oldline + '">'));
|
||||||
|
|
||||||
var tmp;
|
let tmp;
|
||||||
if (typeof oldline !== 'undefined') {
|
if (typeof oldline !== 'undefined') {
|
||||||
if (typeof newline !== 'undefined') {
|
if (typeof newline !== 'undefined') {
|
||||||
tmp = getInlineContainer();
|
tmp = getInlineContainer();
|
||||||
@@ -399,16 +424,19 @@ $(function(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderDiffs(){
|
function renderDiffs() {
|
||||||
var i = 0, diffs = $('.diffText');
|
const diffs = $('.diffText');
|
||||||
|
let i = 0;
|
||||||
function render(){
|
function render(){
|
||||||
if(diffs[i]){
|
if (diffs[i]) {
|
||||||
var $table = renderOneDiff($(diffs[i]), window.viewType);
|
const $table = renderOneDiff($(diffs[i]), window.viewType, $('.file-hash')[i].id);
|
||||||
@if(hasWritePermission) {
|
@if(hasWritePermission) {
|
||||||
renderReplyComment($table);
|
renderReplyComment($table);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
setTimeout(render);
|
setTimeout(render);
|
||||||
|
} else {
|
||||||
|
updateHighlighting();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
render();
|
render();
|
||||||
@@ -416,7 +444,7 @@ $(function(){
|
|||||||
});
|
});
|
||||||
|
|
||||||
function changeDisplaySetting(key, value){
|
function changeDisplaySetting(key, value){
|
||||||
var url = '';
|
let url = '';
|
||||||
window.params[key] = value;
|
window.params[key] = value;
|
||||||
for(key in window.params){
|
for(key in window.params){
|
||||||
if(window.params[key] != ''){
|
if(window.params[key] != ''){
|
||||||
@@ -429,4 +457,47 @@ function changeDisplaySetting(key, value){
|
|||||||
}
|
}
|
||||||
location.href = url;
|
location.href = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let scrolling = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Highlight lines which are specified by URL hash.
|
||||||
|
*/
|
||||||
|
function updateHighlighting(){
|
||||||
|
const hash = location.hash;
|
||||||
|
$('tr.highlight').removeClass('highlight');
|
||||||
|
if (hash.match(/#diff-(\w+)-[LR]\d+(-[LR]\d+)?/)) {
|
||||||
|
const fragments = hash.substr(1).split('-');
|
||||||
|
if (fragments.length == 3) {
|
||||||
|
const tr = $('th#diff-' + fragments[1] + '-' + fragments[2]).closest('tr');
|
||||||
|
tr.addClass('highlight');
|
||||||
|
if(!scrolling){
|
||||||
|
$(window).scrollTop($('th#diff-' + fragments[1] + '-' + fragments[2]).closest('tr').offset().top);
|
||||||
|
}
|
||||||
|
} else if (fragments.length > 3) {
|
||||||
|
let highlight = false;
|
||||||
|
$('th[id^=diff-' + fragments[1] + '-').each(function(i, th) {
|
||||||
|
if (th.id.split('-')[2] == fragments[2]) { // start
|
||||||
|
highlight = true;
|
||||||
|
$(th.closest('tr')).addClass('highlight');
|
||||||
|
} else if (highlight == true) {
|
||||||
|
if (th.id.split('-')[2] == fragments[3]) { // end
|
||||||
|
$(th.closest('tr')).addClass('highlight');
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$(th.closest('tr')).addClass('highlight');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(!scrolling){
|
||||||
|
$(window).scrollTop($('th#diff-' + fragments[1] + '-' + fragments[2]).closest('tr').offset().top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (hash != ''){
|
||||||
|
if (!scrolling) {
|
||||||
|
$(window).scrollTop($(hash).offset().top);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scrolling = true;
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -106,17 +106,15 @@
|
|||||||
}
|
}
|
||||||
<script>
|
<script>
|
||||||
$(window).on('load', function(){
|
$(window).on('load', function(){
|
||||||
updateHighlighting();
|
|
||||||
|
|
||||||
window.onhashchange = function(){
|
window.onhashchange = function(){
|
||||||
updateHighlighting();
|
updateHighlighting();
|
||||||
}
|
}
|
||||||
|
|
||||||
var pre = $('pre.prettyprint');
|
const pre = $('pre.prettyprint');
|
||||||
function updateSourceLineNum(){
|
function updateSourceLineNum() {
|
||||||
$('.source-line-num').remove();
|
$('.source-line-num').remove();
|
||||||
var pos = pre.find('ol.linenums').position();
|
const pos = pre.find('ol.linenums').position();
|
||||||
if(pos){
|
if (pos) {
|
||||||
$('<div class="source-line-num">').css({
|
$('<div class="source-line-num">').css({
|
||||||
height : pre.height(),
|
height : pre.height(),
|
||||||
width : '48px',
|
width : '48px',
|
||||||
@@ -125,34 +123,40 @@ $(window).on('load', function(){
|
|||||||
top : pos.top + 'px',
|
top : pos.top + 'px',
|
||||||
left : pos.left + 'px'
|
left : pos.left + 'px'
|
||||||
}).click(function(e){
|
}).click(function(e){
|
||||||
var pos = $(this).data("pos");
|
let pos = $(this).data("pos");
|
||||||
if(!pos){
|
if (!pos) {
|
||||||
pos = $('ol.linenums li').map(function(){ return { id: $(this).attr("id"), top: $(this).position().top} }).toArray();
|
pos = $('ol.linenums li').map(function(){ return { id: $(this).attr("id"), top: $(this).position().top} }).toArray();
|
||||||
$(this).data("pos",pos);
|
$(this).data("pos",pos);
|
||||||
}
|
}
|
||||||
for(var i = 0; i < pos.length-1; i++){
|
let i = 0;
|
||||||
|
for(i = 0; i < pos.length - 1; i++){
|
||||||
if(pos[i + 1].top > e.pageY){
|
if(pos[i + 1].top > e.pageY){
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var line = pos[i].id.replace(/^L/,'');
|
const line = pos[i].id.replace(/^L/,'');
|
||||||
var hash = location.hash;
|
const hash = location.hash;
|
||||||
var commitUrl = '@helpers.url(repository)/blob/@helpers.encodeRefName((latestCommit.id :: pathList).mkString("/"))';
|
const baseUrl = location.toString().split("#")[0];
|
||||||
if(e.shiftKey == true && hash.match(/#L\d+(-L\d+)?/)){
|
if (e.shiftKey == true && hash.match(/#L\d+(-L\d+)?/)) {
|
||||||
var lines = hash.split('-');
|
const fragments = hash.split('-');
|
||||||
window.history.pushState('', '', commitUrl + lines[0] + '-L' + line);
|
window.history.pushState('', '', baseUrl + fragments[0] + '-L' + line);
|
||||||
} else {
|
} else {
|
||||||
var p = $("#L"+line).attr('id',"");
|
const p = $("#L" + line).attr('id', '');
|
||||||
window.history.pushState('', '', commitUrl + '#L' + line);
|
window.history.pushState('', '', baseUrl + '#L' + line);
|
||||||
p.attr('id','L'+line);
|
p.attr('id','L' + line);
|
||||||
}
|
}
|
||||||
$("#branchCtrlWrapper .btn .muted").text("tree:");
|
$("#branchCtrlWrapper .btn .muted").text("tree:");
|
||||||
$("#branchCtrlWrapper .btn .strong").text("@latestCommit.id.substring(0, 10)");
|
$("#branchCtrlWrapper .btn .strong").text("@latestCommit.id.substring(0, 10)");
|
||||||
|
getSelection().empty();
|
||||||
updateHighlighting();
|
updateHighlighting();
|
||||||
}).appendTo(pre);
|
}).appendTo(pre);
|
||||||
|
updateHighlighting();
|
||||||
|
} else {
|
||||||
|
// Maybe code view is not initialized yet. Retry until succeed.
|
||||||
|
setTimeout(updateSourceLineNum, 300);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var repository = $('.blame-action').data('repository');
|
const repository = $('.blame-action').data('repository');
|
||||||
$('.blame-action').click(function(e){
|
$('.blame-action').click(function(e){
|
||||||
if(history.pushState && $('pre.prettyprint.no-renderable').length){
|
if(history.pushState && $('pre.prettyprint.no-renderable').length){
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@@ -162,44 +166,45 @@ $(window).on('load', function(){
|
|||||||
});
|
});
|
||||||
|
|
||||||
function updateBlame(){
|
function updateBlame(){
|
||||||
var m = /\/(blame|blob)(\/.*)$/.exec(location.href);
|
const m = /\/(blame|blob)(\/.*)$/.exec(location.href);
|
||||||
var mode = m[1];
|
const mode = m[1];
|
||||||
$('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1] == 'blame' ? '/blob' : '/blame') + m[2]);
|
$('.blame-action').toggleClass("active", mode=='blame').attr('href', repository + (m[1] == 'blame' ? '/blob' : '/blame') + m[2]);
|
||||||
if(pre.parents("div.box-content-bottom").find(".blame").length){
|
if(pre.parents("div.box-content-bottom").find(".blame").length){
|
||||||
pre.parent().toggleClass("blame-container", mode == 'blame');
|
pre.parent().toggleClass("blame-container", mode == 'blame');
|
||||||
updateSourceLineNum();
|
updateSourceLineNum();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(mode=='blob'){
|
if(mode == 'blob'){
|
||||||
updateSourceLineNum();
|
updateSourceLineNum();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$(document.body).toggleClass('no-box-shadow', document.body.style.boxShadow === undefined);
|
$(document.body).toggleClass('no-box-shadow', document.body.style.boxShadow === undefined);
|
||||||
$('.blame-action').addClass("active");
|
$('.blame-action').addClass("active");
|
||||||
var base = $('<div class="blame">').css({height: pre.height()}).prependTo(pre.parents("div.box-content-bottom"));
|
const base = $('<div class="blame">').css({height: pre.height()}).prependTo(pre.parents("div.box-content-bottom"));
|
||||||
base.parent().addClass("blame-container");
|
base.parent().addClass("blame-container");
|
||||||
updateSourceLineNum();
|
updateSourceLineNum();
|
||||||
$.get($('.blame-action').data('url')).done(function(data){
|
$.get($('.blame-action').data('url')).done(function(data){
|
||||||
var blame = data.blame;
|
let blame = data.blame;
|
||||||
var index = [];
|
let lastDiv;
|
||||||
for(var i = 0; i < blame.length; i++){
|
const now = new Date().getTime();
|
||||||
for(var j = 0; j < blame[i].lines.length; j++){
|
const index = [];
|
||||||
|
for(let i = 0; i < blame.length; i++){
|
||||||
|
for(let j = 0; j < blame[i].lines.length; j++){
|
||||||
index[blame[i].lines[j]] = blame[i];
|
index[blame[i].lines[j]] = blame[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var blame, lastDiv, now = new Date().getTime();
|
|
||||||
|
|
||||||
$('pre.prettyprint ol.linenums li').each(function(i, e){
|
$('pre.prettyprint ol.linenums li').each(function(i, e){
|
||||||
var p = $(e).position();
|
const p = $(e).position();
|
||||||
var h = $(e).height();
|
const h = $(e).height();
|
||||||
if(blame == index[i]){
|
if(blame == index[i]){
|
||||||
lastDiv.css("min-height",(p.top + h + 1) - lastDiv.position().top);
|
lastDiv.css("min-height",(p.top + h + 1) - lastDiv.position().top);
|
||||||
} else {
|
} else {
|
||||||
$(e).addClass('blame-sep')
|
$(e).addClass('blame-sep')
|
||||||
blame = index[i];
|
blame = index[i];
|
||||||
var sha = $('<div class="blame-sha">')
|
const sha = $('<div class="blame-sha">')
|
||||||
.append($('<a>').attr("href", data.root + '/commit/' + blame.id).text(blame.id.substr(0,7)));
|
.append($('<a>').attr("href", data.root + '/commit/' + blame.id).text(blame.id.substr(0, 7)));
|
||||||
if(blame.prev){
|
if (blame.prev) {
|
||||||
sha.append($('<br />'))
|
sha.append($('<br />'))
|
||||||
.append($('<a class="muted-link">').text('prev').attr("href", data.root + '/blame/' + blame.prev + '/' + (blame.prevPath || data.path)));
|
.append($('<a class="muted-link">').text('prev').attr("href", data.root + '/blame/' + blame.prev + '/' + (blame.prevPath || data.path)));
|
||||||
}
|
}
|
||||||
@@ -221,51 +226,53 @@ $(window).on('load', function(){
|
|||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
$(document).on('expanded.pushMenu collapsed.pushMenu', function(e){
|
$(document).on('expanded.pushMenu collapsed.pushMenu', function(e){
|
||||||
setTimeout(updateBlame, 300);
|
setTimeout(updateBlame, 300);
|
||||||
});
|
});
|
||||||
|
|
||||||
updateBlame();
|
updateBlame();
|
||||||
});
|
});
|
||||||
|
|
||||||
var scrolling = false;
|
let scrolling = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hightlight lines which are specified by URL hash.
|
* Highlight lines which are specified by URL hash.
|
||||||
*/
|
*/
|
||||||
function updateHighlighting(){
|
function updateHighlighting() {
|
||||||
var hash = location.hash;
|
const hash = location.hash;
|
||||||
var isDark = @{highlighterTheme.contains("dark").toString};
|
const isDark = @{highlighterTheme.contains("dark").toString};
|
||||||
if(hash.match(/#L\d+(-L\d+)?/)){
|
if (hash.match(/#L\d+(-L\d+)?/)) {
|
||||||
if(isDark){
|
if (isDark) {
|
||||||
$('li.highlight').removeClass('highlight-dark');
|
$('li.highlight').removeClass('highlight-dark');
|
||||||
}else{
|
} else {
|
||||||
$('li.highlight').removeClass('highlight');
|
$('li.highlight').removeClass('highlight');
|
||||||
}
|
}
|
||||||
var lines = hash.substr(1).split('-');
|
const fragments = hash.substr(1).split('-');
|
||||||
if(lines.length == 1){
|
if (fragments.length == 1) {
|
||||||
if(isDark){
|
if (isDark) {
|
||||||
$('#' + lines[0]).addClass('highlight-dark');
|
$('#' + fragments[0]).addClass('highlight-dark');
|
||||||
}else{
|
} else {
|
||||||
$('#' + lines[0]).addClass('highlight');
|
$('#' + fragments[0]).addClass('highlight');
|
||||||
}
|
}
|
||||||
if(!scrolling){
|
if(!scrolling){
|
||||||
$(window).scrollTop($('#' + lines[0]).offset().top - 40);
|
$(window).scrollTop($('#' + fragments[0]).offset().top);
|
||||||
}
|
}
|
||||||
} else if(lines.length > 1){
|
} else if(fragments.length > 1){
|
||||||
var start = parseInt(lines[0].substr(1));
|
const start = parseInt(fragments[0].substr(1));
|
||||||
var end = parseInt(lines[1].substr(1));
|
const end = parseInt(fragments[1].substr(1));
|
||||||
for(var i = start; i <= end; i++){
|
for (let i = start; i <= end; i++) {
|
||||||
if(isDark){
|
if (isDark) {
|
||||||
$('#L' + i).addClass('highlight-dark');
|
$('#L' + i).addClass('highlight-dark');
|
||||||
}else{
|
} else {
|
||||||
$('#L' + i).addClass('highlight');
|
$('#L' + i).addClass('highlight');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!scrolling){
|
if (!scrolling) {
|
||||||
$(window).scrollTop($('#L' + start).offset().top - 40);
|
$(window).scrollTop($('#' + fragments[0]).offset().top);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scrolling = true;
|
|
||||||
}
|
}
|
||||||
|
scrolling = true;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -292,6 +292,7 @@ div.box-content-bottom img {
|
|||||||
|
|
||||||
table.table th.box-header {
|
table.table th.box-header {
|
||||||
background-color: #f5f5f5;
|
background-color: #f5f5f5;
|
||||||
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
th.box-header .octicon {
|
th.box-header .octicon {
|
||||||
@@ -604,8 +605,11 @@ div.markdown-body pre.plain {
|
|||||||
padding: 20px;
|
padding: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
li.highlight {
|
li.highlight,
|
||||||
|
table.diff tr.highlight>th.delete, table.diff tr.highlight>th.insert, table.diff tr.highlight>th.equal,
|
||||||
|
table.diff tr.highlight>td.delete, table.diff tr.highlight>td.insert, table.diff tr.highlight>td.equal {
|
||||||
background-color: #ffb;
|
background-color: #ffb;
|
||||||
|
!important
|
||||||
}
|
}
|
||||||
|
|
||||||
li.highlight-dark {
|
li.highlight-dark {
|
||||||
|
|||||||
@@ -74,21 +74,24 @@ function displayErrors(data, elem){
|
|||||||
* @param outputId {String} element id of output element
|
* @param outputId {String} element id of output element
|
||||||
* @param viewType {Number} 0: split, 1: unified
|
* @param viewType {Number} 0: split, 1: unified
|
||||||
* @param ignoreSpace {Number} 0: include, 1: ignore
|
* @param ignoreSpace {Number} 0: include, 1: ignore
|
||||||
|
* @param fileHash {SString} hash used for links to line numbers
|
||||||
*/
|
*/
|
||||||
function diffUsingJS(oldTextId, newTextId, outputId, viewType, ignoreSpace) {
|
function diffUsingJS(oldTextId, newTextId, outputId, viewType, ignoreSpace, fileHash) {
|
||||||
var old = $('#' + oldTextId), head = $('#' + newTextId);
|
const old = $('#' + oldTextId), head = $('#' + newTextId);
|
||||||
|
let oldTextValue, headTextValue;
|
||||||
old.is("textarea") ? (oldTextValue = old.data('val')) : (oldTextValue = old.attr('data-val'));
|
old.is("textarea") ? (oldTextValue = old.data('val')) : (oldTextValue = old.attr('data-val'));
|
||||||
head.is("textarea") ? (headTextvalue = head.data('val')) : (headTextValue = head.attr('data-val'));
|
head.is("textarea") ? (headTextValue = head.data('val')) : (headTextValue = head.attr('data-val'));
|
||||||
var render = new JsDiffRender({
|
const render = new JsDiffRender({
|
||||||
oldText : oldTextValue,
|
oldText : oldTextValue,
|
||||||
oldTextName: old.data('file-name'),
|
oldTextName: old.data('file-name'),
|
||||||
newText : headTextValue,
|
newText : headTextValue,
|
||||||
newTextName: head.data('file-name'),
|
newTextName: head.data('file-name'),
|
||||||
ignoreSpace: ignoreSpace,
|
ignoreSpace: ignoreSpace,
|
||||||
contextSize: 4
|
contextSize: 4,
|
||||||
|
fileHash : fileHash
|
||||||
});
|
});
|
||||||
var diff = render[viewType == 1 ? "unified" : "split"]();
|
const diff = render[viewType == 1 ? "unified" : "split"]();
|
||||||
if(viewType == 1){
|
if (viewType == 1) {
|
||||||
diff.find('tr:last').after($('<tr><td></td><td></td><td></td></tr>'));
|
diff.find('tr:last').after($('<tr><td></td><td></td><td></td></tr>'));
|
||||||
} else {
|
} else {
|
||||||
diff.find('tr:last').after($('<tr><td></td><td></td><td></td><td></td></tr>'));
|
diff.find('tr:last').after($('<tr><td></td><td></td><td></td><td></td></tr>'));
|
||||||
@@ -102,222 +105,224 @@ function jqSelectorEscape(val) {
|
|||||||
return val.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&');
|
return val.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, '\\$&');
|
||||||
}
|
}
|
||||||
|
|
||||||
function JsDiffRender(params){
|
function JsDiffRender(params) {
|
||||||
var baseTextLines = (params.oldText==="")?[]:params.oldText.split(/\r\n|\r|\n/);
|
const baseTextLines = (params.oldText==="")?[]:params.oldText.split(/\r\n|\r|\n/);
|
||||||
var headTextLines = (params.newText==="")?[]:params.newText.split(/\r\n|\r|\n/);
|
const headTextLines = (params.newText==="")?[]:params.newText.split(/\r\n|\r|\n/);
|
||||||
var sm, ctx;
|
let sm, ctx;
|
||||||
if(params.ignoreSpace){
|
if (params.ignoreSpace) {
|
||||||
var ignoreSpace = function(a){ return a.replace(/\s+/g,''); };
|
const ignoreSpace = function(a){ return a.replace(/\s+/g,''); };
|
||||||
sm = new difflib.SequenceMatcher(
|
sm = new difflib.SequenceMatcher(
|
||||||
$.map(baseTextLines, ignoreSpace),
|
$.map(baseTextLines, ignoreSpace),
|
||||||
$.map(headTextLines, ignoreSpace));
|
$.map(headTextLines, ignoreSpace));
|
||||||
ctx = this.flatten(sm.get_opcodes(), headTextLines, baseTextLines, function(text){ return ignoreSpace(text) === ""; });
|
ctx = this.flatten(sm.get_opcodes(), headTextLines, baseTextLines, function(text){ return ignoreSpace(text) === ""; });
|
||||||
}else{
|
} else {
|
||||||
sm = new difflib.SequenceMatcher(baseTextLines, headTextLines);
|
sm = new difflib.SequenceMatcher(baseTextLines, headTextLines);
|
||||||
ctx = this.flatten(sm.get_opcodes(), headTextLines, baseTextLines, function(){ return false; });
|
ctx = this.flatten(sm.get_opcodes(), headTextLines, baseTextLines, function(){ return false; });
|
||||||
}
|
}
|
||||||
var oplines = this.fold(ctx, params.contextSize);
|
const oplines = this.fold(ctx, params.contextSize);
|
||||||
|
|
||||||
function prettyDom(text, fileName){
|
function prettyDom(text, fileName){
|
||||||
var dom = null;
|
let dom = null;
|
||||||
return function(ln){
|
return function(ln) {
|
||||||
if(dom===null){
|
if(dom === null) {
|
||||||
var html = prettyPrintOne(
|
const html = prettyPrintOne(
|
||||||
text.replace(/&/g,'&').replace(/</g,'<').replace(/"/g,'"').replace(/>/g,'>').replace(/^\n/, '\n\n'),
|
text.replace(/&/g,'&').replace(/</g,'<').replace(/"/g,'"').replace(/>/g,'>').replace(/^\n/, '\n\n'),
|
||||||
(/\.([^.]*)$/.exec(fileName)||[])[1],
|
(/\.([^.]*)$/.exec(fileName)||[])[1],
|
||||||
true);
|
true);
|
||||||
var re = /<li[^>]*id="?L([0-9]+)"?[^>]*>(.*?)<\/li>/gi, h;
|
const re = /<li[^>]*id="?L([0-9]+)"?[^>]*>(.*?)<\/li>/gi;
|
||||||
dom=[];
|
let h;
|
||||||
while(h=re.exec(html)){
|
dom = [];
|
||||||
dom[h[1]]=h[2];
|
while (h = re.exec(html)) {
|
||||||
|
dom[h[1]] = h[2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dom[ln];
|
return dom[ln];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return this.renders(oplines, prettyDom(params.oldText, params.oldTextName), prettyDom(params.newText, params.newTextName));
|
return this.renders(oplines, prettyDom(params.oldText, params.oldTextName), prettyDom(params.newText, params.newTextName), params.fileHash);
|
||||||
}
|
}
|
||||||
$.extend(JsDiffRender.prototype,{
|
$.extend(JsDiffRender.prototype,{
|
||||||
renders: function(oplines, baseTextDom, headTextDom){
|
renders: function(oplines, baseTextDom, headTextDom, fileHash){
|
||||||
return {
|
return {
|
||||||
split:function(){
|
split: function(){
|
||||||
var table = $('<table class="diff">');
|
const table = $('<table class="diff">');
|
||||||
table.attr({add:oplines.add, del:oplines.del});
|
table.attr({ add: oplines.add, del: oplines.del });
|
||||||
var tbody = $('<tbody>').appendTo(table);
|
const tbody = $('<tbody>').appendTo(table);
|
||||||
for(var i=0;i<oplines.length;i++){
|
for (let i = 0; i < oplines.length; i++) {
|
||||||
var o = oplines[i];
|
const o = oplines[i];
|
||||||
switch(o.change){
|
switch (o.change) {
|
||||||
case 'skip':
|
case 'skip':
|
||||||
$('<tr>').html('<th class="skip"></th><td colspan="3" class="skip">...</td>').appendTo(tbody);
|
$('<tr>').html('<th class="skip"></th><td colspan="3" class="skip">...</td>').appendTo(tbody);
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
case 'insert':
|
case 'insert':
|
||||||
case 'equal':
|
case 'equal':
|
||||||
$('<tr>').append(
|
$('<tr>').append(
|
||||||
lineNum('old',o.base, o.change),
|
lineNum('old', o.base, o.change, fileHash),
|
||||||
$('<td class="body">').html(o.base ? baseTextDom(o.base): "").addClass(o.change),
|
$('<td class="body">').html(o.base ? baseTextDom(o.base): "").addClass(o.change),
|
||||||
lineNum('new',o.head, o.change),
|
lineNum('new', o.head, o.change, fileHash),
|
||||||
$('<td class="body">').html(o.head ? headTextDom(o.head): "").addClass(o.change)
|
$('<td class="body">').html(o.head ? headTextDom(o.head): "").addClass(o.change)
|
||||||
).appendTo(tbody);
|
).appendTo(tbody);
|
||||||
break;
|
break;
|
||||||
case 'replace':
|
case 'replace':
|
||||||
var ld = lineDiff(baseTextDom(o.base), headTextDom(o.head));
|
const ld = lineDiff(baseTextDom(o.base), headTextDom(o.head));
|
||||||
$('<tr>').append(
|
$('<tr>').append(
|
||||||
lineNum('old',o.base, 'delete'),
|
lineNum('old', o.base, 'delete', fileHash),
|
||||||
$('<td class="body">').append(ld.base).addClass('delete'),
|
$('<td class="body">').append(ld.base).addClass('delete'),
|
||||||
lineNum('new',o.head, 'insert'),
|
lineNum('new', o.head, 'insert', fileHash),
|
||||||
$('<td class="body">').append(ld.head).addClass('insert')
|
$('<td class="body">').append(ld.head).addClass('insert')
|
||||||
).appendTo(tbody);
|
).appendTo(tbody);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
},
|
},
|
||||||
unified:function(){
|
unified: function(){
|
||||||
var table = $('<table class="diff inlinediff">');
|
const table = $('<table class="diff inlinediff">');
|
||||||
table.attr({add:oplines.add, del:oplines.del});
|
table.attr({ add: oplines.add, del: oplines.del });
|
||||||
var tbody = $('<tbody>').appendTo(table);
|
const tbody = $('<tbody>').appendTo(table);
|
||||||
for(var i=0;i<oplines.length;i++){
|
for (let i = 0; i < oplines.length; i++) {
|
||||||
var o = oplines[i];
|
const o = oplines[i];
|
||||||
switch(o.change){
|
switch (o.change) {
|
||||||
case 'skip':
|
case 'skip':
|
||||||
tbody.append($('<tr>').html('<th colspan="2" class="skip"></th><td class="skip"></td>'));
|
tbody.append($('<tr>').html('<th colspan="2" class="skip"></th><td class="skip"></td>'));
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
case 'insert':
|
case 'insert':
|
||||||
case 'equal':
|
case 'equal':
|
||||||
tbody.append($('<tr>').append(
|
tbody.append($('<tr>').append(
|
||||||
lineNum('old',o.base, o.change),
|
lineNum('old', o.base, o.change, fileHash),
|
||||||
lineNum('new',o.head, o.change),
|
lineNum('new', o.head, o.change, fileHash),
|
||||||
$('<td class="body">').addClass(o.change).html(o.head ? headTextDom(o.head) : baseTextDom(o.base))));
|
$('<td class="body">').addClass(o.change).html(o.head ? headTextDom(o.head) : baseTextDom(o.base))));
|
||||||
break;
|
break;
|
||||||
case 'replace':
|
case 'replace':
|
||||||
var deletes = [];
|
const deletes = [];
|
||||||
while(oplines[i] && oplines[i].change == 'replace'){
|
while (oplines[i] && oplines[i].change == 'replace') {
|
||||||
if(oplines[i].base && oplines[i].head){
|
if (oplines[i].base && oplines[i].head) {
|
||||||
var ld = lineDiff(baseTextDom(oplines[i].base), headTextDom(oplines[i].head));
|
const ld = lineDiff(baseTextDom(oplines[i].base), headTextDom(oplines[i].head));
|
||||||
tbody.append($('<tr>').append(lineNum('old', oplines[i].base, 'delete'),'<th class="delete">',$('<td class="body delete">').append(ld.base)));
|
tbody.append($('<tr>').append(lineNum('old', oplines[i].base, 'delete', fileHash), '<th class="delete">', $('<td class="body delete">').append(ld.base)));
|
||||||
deletes.push($('<tr>').append('<th class="insert">',lineNum('new',oplines[i].head, 'insert'),$('<td class="body insert">').append(ld.head)));
|
deletes.push($('<tr>').append('<th class="insert">',lineNum('new', oplines[i].head, 'insert', fileHash),$('<td class="body insert">').append(ld.head)));
|
||||||
}else if(oplines[i].base){
|
} else if(oplines[i].base) {
|
||||||
tbody.append($('<tr>').append(lineNum('old', oplines[i].base, 'delete'),'<th class="delete">',$('<td class="body delete">').html(baseTextDom(oplines[i].base))));
|
tbody.append($('<tr>').append(lineNum('old', oplines[i].base, 'delete', fileHash), '<th class="delete">', $('<td class="body delete">').html(baseTextDom(oplines[i].base))));
|
||||||
}else if(oplines[i].head){
|
} else if(oplines[i].head) {
|
||||||
deletes.push($('<tr>').append('<th class="insert">',lineNum('new',oplines[i].head, 'insert'),$('<td class="body insert">').html(headTextDom(oplines[i].head))));
|
deletes.push($('<tr>').append('<th class="insert">',lineNum('new', oplines[i].head, 'insert', fileHash), $('<td class="body insert">').html(headTextDom(oplines[i].head))));
|
||||||
|
}
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
i++;
|
tbody.append(deletes);
|
||||||
}
|
i--;
|
||||||
tbody.append(deletes);
|
break;
|
||||||
i--;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
function lineNum(type, num, klass){
|
function lineNum(type, num, klass, hash) {
|
||||||
var cell = $('<th class="line-num">').addClass(type+'line').addClass(klass);
|
const cell = $('<th class="line-num">').addClass(type + 'line').addClass(klass);
|
||||||
if(num){
|
if (num) {
|
||||||
cell.attr('line-number',num);
|
cell.attr('line-number', num);
|
||||||
|
cell.attr('id', hash + '-' + (type == 'old' ? 'L' : 'R') + num);
|
||||||
}
|
}
|
||||||
return cell;
|
return cell;
|
||||||
}
|
}
|
||||||
function lineDiff(b,n){
|
function lineDiff(b, n) {
|
||||||
var bc = $('<diff>').html(b).children();
|
const bc = $('<diff>').html(b).children();
|
||||||
var nc = $('<diff>').html(n).children();
|
const nc = $('<diff>').html(n).children();
|
||||||
var textE = function(){ return $(this).text(); };
|
const textE = function(){ return $(this).text(); };
|
||||||
var sm = new difflib.SequenceMatcher(bc.map(textE), nc.map(textE));
|
const sm = new difflib.SequenceMatcher(bc.map(textE), nc.map(textE));
|
||||||
var op = sm.get_opcodes();
|
const op = sm.get_opcodes();
|
||||||
if(op.length==1 || sm.ratio()<0.5){
|
if (op.length == 1 || sm.ratio() < 0.5) {
|
||||||
return {base:bc,head:nc};
|
return { base:bc, head:nc };
|
||||||
}
|
}
|
||||||
var ret = { base : [], head: []};
|
const ret = { base : [], head: []};
|
||||||
for(var i=0;i<op.length;i++){
|
for (let i = 0; i < op.length; i++) {
|
||||||
var o = op[i];
|
const o = op[i];
|
||||||
switch(o[0]){
|
switch (o[0]) {
|
||||||
case 'equal':
|
case 'equal':
|
||||||
ret.base=ret.base.concat(bc.slice(o[1],o[2]));
|
ret.base = ret.base.concat(bc.slice(o[1], o[2]));
|
||||||
ret.head=ret.head.concat(nc.slice(o[3],o[4]));
|
ret.head = ret.head.concat(nc.slice(o[3], o[4]));
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
case 'insert':
|
case 'insert':
|
||||||
case 'replace':
|
case 'replace':
|
||||||
if(o[2]!=o[1]){
|
if(o[2] != o[1]){
|
||||||
ret.base.push($('<del>').append(bc.slice(o[1],o[2])));
|
ret.base.push($('<del>').append(bc.slice(o[1], o[2])));
|
||||||
}
|
}
|
||||||
if(o[4]!=o[3]){
|
if(o[4] != o[3]){
|
||||||
ret.head.push($('<ins>').append(nc.slice(o[3],o[4])));
|
ret.head.push($('<ins>').append(nc.slice(o[3], o[4])));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
flatten: function(opcodes, headTextLines, baseTextLines, isIgnoreLine){
|
flatten: function(opcodes, headTextLines, baseTextLines, isIgnoreLine){
|
||||||
var ret = [], add=0, del=0;
|
let ret = [], add = 0, del = 0;
|
||||||
for (var idx = 0; idx < opcodes.length; idx++) {
|
for (let idx = 0; idx < opcodes.length; idx++) {
|
||||||
var code = opcodes[idx];
|
const code = opcodes[idx];
|
||||||
var change = code[0];
|
const change = code[0];
|
||||||
var b = code[1];
|
let b = code[1];
|
||||||
var n = code[3];
|
let n = code[3];
|
||||||
var rowcnt = Math.max(code[2] - b, code[4] - n);
|
const rowcnt = Math.max(code[2] - b, code[4] - n);
|
||||||
for (var i = 0; i < rowcnt; i++) {
|
for (let i = 0; i < rowcnt; i++) {
|
||||||
switch(change){
|
switch(change){
|
||||||
case 'insert':
|
case 'insert':
|
||||||
add++;
|
add++;
|
||||||
ret.push({
|
ret.push({
|
||||||
change:(isIgnoreLine(headTextLines[n]) ? 'equal' : change),
|
change:(isIgnoreLine(headTextLines[n]) ? 'equal' : change),
|
||||||
head: ++n
|
head: ++n
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'delete':
|
case 'delete':
|
||||||
del++;
|
del++;
|
||||||
ret.push({
|
ret.push({
|
||||||
change: (isIgnoreLine(baseTextLines[b]) ? 'equal' : change),
|
change: (isIgnoreLine(baseTextLines[b]) ? 'equal' : change),
|
||||||
base: ++b
|
base: ++b
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'replace':
|
case 'replace':
|
||||||
add++;
|
add++;
|
||||||
del++;
|
del++;
|
||||||
var r = {change: change};
|
const r = { change: change };
|
||||||
if(n<code[4]){
|
if (n<code[4]) {
|
||||||
r.head = ++n;
|
r.head = ++n;
|
||||||
}
|
}
|
||||||
if(b<code[2]){
|
if (b<code[2]) {
|
||||||
r.base = ++b;
|
r.base = ++b;
|
||||||
}
|
}
|
||||||
ret.push(r);
|
ret.push(r);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret.push({
|
ret.push({
|
||||||
change:change,
|
change:change,
|
||||||
head: ++n,
|
head: ++n,
|
||||||
base: ++b
|
base: ++b
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret.add=add;
|
ret.add = add;
|
||||||
ret.del=del;
|
ret.del = del;
|
||||||
return ret;
|
return ret;
|
||||||
},
|
},
|
||||||
fold: function(oplines, contextSize){
|
fold: function(oplines, contextSize){
|
||||||
var ret = [], skips=[], bskip = contextSize;
|
let ret = [], skips=[], bskip = contextSize;
|
||||||
for(var i=0;i<oplines.length;i++){
|
for (let i = 0; i < oplines.length; i++) {
|
||||||
var o = oplines[i];
|
const o = oplines[i];
|
||||||
if(o.change=='equal'){
|
if (o.change=='equal') {
|
||||||
if(bskip < contextSize){
|
if (bskip < contextSize) {
|
||||||
bskip ++;
|
bskip ++;
|
||||||
ret.push(o);
|
ret.push(o);
|
||||||
}else{
|
} else {
|
||||||
skips.push(o);
|
skips.push(o);
|
||||||
}
|
}
|
||||||
}else{
|
} else {
|
||||||
if(skips.length > contextSize){
|
if (skips.length > contextSize) {
|
||||||
ret.push({
|
ret.push({
|
||||||
change:'skip',
|
change: 'skip',
|
||||||
start:skips[0],
|
start: skips[0],
|
||||||
end:skips[skips.length-contextSize]
|
end: skips[skips.length-contextSize]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
ret = ret.concat(skips.splice(- contextSize));
|
ret = ret.concat(skips.splice(- contextSize));
|
||||||
@@ -326,7 +331,7 @@ $.extend(JsDiffRender.prototype,{
|
|||||||
bskip = 0;
|
bskip = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(skips.length > contextSize){
|
if (skips.length > contextSize) {
|
||||||
ret.push({
|
ret.push({
|
||||||
change:'skip',
|
change:'skip',
|
||||||
start:skips[0],
|
start:skips[0],
|
||||||
@@ -344,12 +349,12 @@ $.extend(JsDiffRender.prototype,{
|
|||||||
*/
|
*/
|
||||||
function scrollIntoView(target){
|
function scrollIntoView(target){
|
||||||
target = $(target);
|
target = $(target);
|
||||||
var $window = $(window);
|
const $window = $(window);
|
||||||
var docViewTop = $window.scrollTop();
|
const docViewTop = $window.scrollTop();
|
||||||
var docViewBottom = docViewTop + $window.height();
|
const docViewBottom = docViewTop + $window.height();
|
||||||
|
|
||||||
var elemTop = target.offset().top;
|
const elemTop = target.offset().top;
|
||||||
var elemBottom = elemTop + target.height();
|
const elemBottom = elemTop + target.height();
|
||||||
|
|
||||||
if(elemBottom > docViewBottom){
|
if(elemBottom > docViewBottom){
|
||||||
$('html, body').scrollTop(elemBottom - $window.height());
|
$('html, body').scrollTop(elemBottom - $window.height());
|
||||||
|
|||||||
Reference in New Issue
Block a user