|
|
|
import $ from 'jquery';
|
|
|
|
import {svg} from '../svg.js';
|
|
|
|
|
|
|
|
function changeHash(hash) {
|
|
|
|
if (window.history.pushState) {
|
|
|
|
window.history.pushState(null, null, hash);
|
|
|
|
} else {
|
|
|
|
window.location.hash = hash;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function selectRange($list, $select, $from) {
|
|
|
|
$list.removeClass('active');
|
|
|
|
|
|
|
|
// add hashchange to permalink
|
|
|
|
const $issue = $('a.ref-in-new-issue');
|
|
|
|
const $copyPermalink = $('a.copy-line-permalink');
|
|
|
|
|
|
|
|
if ($issue.length === 0 || $copyPermalink.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const updateIssueHref = function(anchor) {
|
|
|
|
let href = $issue.attr('href');
|
|
|
|
href = `${href.replace(/%23L\d+$|%23L\d+-L\d+$/, '')}%23${anchor}`;
|
|
|
|
$issue.attr('href', href);
|
|
|
|
};
|
|
|
|
|
|
|
|
const updateCopyPermalinkHref = function(anchor) {
|
|
|
|
let link = $copyPermalink.attr('data-clipboard-text');
|
|
|
|
link = `${link.replace(/#L\d+$|#L\d+-L\d+$/, '')}#${anchor}`;
|
|
|
|
$copyPermalink.attr('data-clipboard-text', link);
|
|
|
|
};
|
|
|
|
|
|
|
|
if ($from) {
|
|
|
|
let a = parseInt($select.attr('rel').substr(1));
|
|
|
|
let b = parseInt($from.attr('rel').substr(1));
|
|
|
|
let c;
|
|
|
|
if (a !== b) {
|
|
|
|
if (a > b) {
|
|
|
|
c = a;
|
|
|
|
a = b;
|
|
|
|
b = c;
|
|
|
|
}
|
|
|
|
const classes = [];
|
|
|
|
for (let i = a; i <= b; i++) {
|
|
|
|
classes.push(`[rel=L${i}]`);
|
|
|
|
}
|
|
|
|
$list.filter(classes.join(',')).addClass('active');
|
|
|
|
changeHash(`#L${a}-L${b}`);
|
|
|
|
|
|
|
|
updateIssueHref(`L${a}-L${b}`);
|
|
|
|
updateCopyPermalinkHref(`L${a}-L${b}`);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$select.addClass('active');
|
|
|
|
changeHash(`#${$select.attr('rel')}`);
|
|
|
|
|
|
|
|
updateIssueHref($select.attr('rel'));
|
|
|
|
updateCopyPermalinkHref($select.attr('rel'));
|
|
|
|
}
|
|
|
|
|
|
|
|
function showLineButton() {
|
|
|
|
if ($('.code-line-menu').length === 0) return;
|
|
|
|
$('.code-line-button').remove();
|
|
|
|
$('.code-view td.lines-code.active').closest('tr').find('td:eq(0)').first().prepend(
|
|
|
|
$(`<button class="code-line-button">${svg('octicon-kebab-horizontal')}</button>`)
|
|
|
|
);
|
|
|
|
$('.code-line-menu').appendTo($('.code-view'));
|
|
|
|
$('.code-line-button').popup({popup: $('.code-line-menu'), on: 'click'});
|
|
|
|
}
|
|
|
|
|
|
|
|
export function initRepoCodeView() {
|
|
|
|
if ($('.code-view .lines-num').length > 0) {
|
|
|
|
$(document).on('click', '.lines-num span', function (e) {
|
|
|
|
const $select = $(this);
|
|
|
|
let $list;
|
|
|
|
if ($('div.blame').length) {
|
|
|
|
$list = $('.code-view td.lines-code.blame-code');
|
|
|
|
} else {
|
|
|
|
$list = $('.code-view td.lines-code');
|
|
|
|
}
|
|
|
|
selectRange($list, $list.filter(`[rel=${$select.attr('id')}]`), (e.shiftKey ? $list.filter('.active').eq(0) : null));
|
|
|
|
|
|
|
|
if (window.getSelection) {
|
|
|
|
window.getSelection().removeAllRanges();
|
|
|
|
} else {
|
|
|
|
document.selection.empty();
|
|
|
|
}
|
|
|
|
|
|
|
|
// show code view menu marker (don't show in blame page)
|
|
|
|
if ($('div.blame').length === 0) {
|
|
|
|
showLineButton();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$(window).on('hashchange', () => {
|
|
|
|
let m = window.location.hash.match(/^#(L\d+)-(L\d+)$/);
|
|
|
|
let $list;
|
|
|
|
if ($('div.blame').length) {
|
|
|
|
$list = $('.code-view td.lines-code.blame-code');
|
|
|
|
} else {
|
|
|
|
$list = $('.code-view td.lines-code');
|
|
|
|
}
|
|
|
|
let $first;
|
|
|
|
if (m) {
|
|
|
|
$first = $list.filter(`[rel=${m[1]}]`);
|
|
|
|
selectRange($list, $first, $list.filter(`[rel=${m[2]}]`));
|
|
|
|
|
|
|
|
// show code view menu marker (don't show in blame page)
|
|
|
|
if ($('div.blame').length === 0) {
|
|
|
|
showLineButton();
|
|
|
|
}
|
|
|
|
|
|
|
|
$('html, body').scrollTop($first.offset().top - 200);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m = window.location.hash.match(/^#(L|n)(\d+)$/);
|
|
|
|
if (m) {
|
|
|
|
$first = $list.filter(`[rel=L${m[2]}]`);
|
|
|
|
selectRange($list, $first);
|
|
|
|
|
|
|
|
// show code view menu marker (don't show in blame page)
|
|
|
|
if ($('div.blame').length === 0) {
|
|
|
|
showLineButton();
|
|
|
|
}
|
|
|
|
|
|
|
|
$('html, body').scrollTop($first.offset().top - 200);
|
|
|
|
}
|
|
|
|
}).trigger('hashchange');
|
|
|
|
}
|
|
|
|
$(document).on('click', '.fold-file', ({currentTarget}) => {
|
|
|
|
const box = currentTarget.closest('.file-content');
|
|
|
|
const folded = box.getAttribute('data-folded') !== 'true';
|
|
|
|
currentTarget.innerHTML = svg(`octicon-chevron-${folded ? 'right' : 'down'}`, 18);
|
|
|
|
box.setAttribute('data-folded', String(folded));
|
|
|
|
});
|
|
|
|
$(document).on('click', '.blob-excerpt', async ({currentTarget}) => {
|
|
|
|
const url = currentTarget.getAttribute('data-url');
|
|
|
|
const query = currentTarget.getAttribute('data-query');
|
|
|
|
const anchor = currentTarget.getAttribute('data-anchor');
|
|
|
|
if (!url) return;
|
|
|
|
const blob = await $.get(`${url}?${query}&anchor=${anchor}`);
|
|
|
|
currentTarget.closest('tr').outerHTML = blob;
|
|
|
|
});
|
|
|
|
}
|