Changeset View
Changeset View
Standalone View
Standalone View
assets/src/bundles/webapp/code-highlighting.js
/** | /** | ||||
* Copyright (C) 2018-2019 The Software Heritage developers | * Copyright (C) 2018-2021 The Software Heritage developers | ||||
* See the AUTHORS file at the top-level directory of this distribution | * See the AUTHORS file at the top-level directory of this distribution | ||||
* License: GNU Affero General Public License version 3, or any later version | * License: GNU Affero General Public License version 3, or any later version | ||||
* See top-level LICENSE file for more information | * See top-level LICENSE file for more information | ||||
*/ | */ | ||||
import {removeUrlFragment} from 'utils/functions'; | import {removeUrlFragment} from 'utils/functions'; | ||||
// keep track of the first highlighted line | // keep track of the first highlighted line | ||||
let firstHighlightedLine = null; | let firstHighlightedLine = null; | ||||
// highlighting color | // highlighting color | ||||
const lineHighlightColor = 'rgb(193, 255, 193)'; | const lineHighlightColor = 'rgb(193, 255, 193)'; | ||||
// function to highlight a line | // function to highlight a line | ||||
export function highlightLine(i, firstHighlighted = false) { | export function highlightLine(i, firstHighlighted = false) { | ||||
const lineTd = $(`.hljs-ln-line[data-line-number="${i}"]`); | const lineTd = $(`.hljs-ln-line[data-line-number="${i}"]`); | ||||
lineTd.css('background-color', lineHighlightColor); | lineTd.css('background-color', lineHighlightColor); | ||||
if (firstHighlighted) { | if (firstHighlighted) { | ||||
firstHighlightedLine = i; | firstHighlightedLine = i; | ||||
} | } | ||||
return lineTd; | return lineTd; | ||||
} | } | ||||
// function to highlight a range of lines | |||||
export function highlightLines(first, last) { | |||||
if (!first) { | |||||
return; | |||||
} | |||||
if (!last) { | |||||
last = first; | |||||
} | |||||
for (let i = first; i <= last; ++i) { | |||||
highlightLine(i); | |||||
} | |||||
} | |||||
// function to reset highlighting | // function to reset highlighting | ||||
export function resetHighlightedLines() { | export function resetHighlightedLines() { | ||||
firstHighlightedLine = null; | firstHighlightedLine = null; | ||||
$('.hljs-ln-line[data-line-number]').css('background-color', 'inherit'); | $('.hljs-ln-line[data-line-number]').css('background-color', 'inherit'); | ||||
} | } | ||||
export function scrollToLine(lineDomElt) { | export function scrollToLine(lineDomElt, offset = 70) { | ||||
if ($(lineDomElt).closest('.swh-content').length > 0) { | if ($(lineDomElt).closest('.swh-content').length > 0) { | ||||
$('html, body').animate({ | $('html, body').animate({ | ||||
scrollTop: $(lineDomElt).offset().top - 70 | scrollTop: $(lineDomElt).offset().top - offset | ||||
}, 500); | }, 500); | ||||
} | } | ||||
} | } | ||||
export async function highlightCode(showLineNumbers = true, selector = 'code') { | export async function highlightCode(showLineNumbers = true, selector = 'code', | ||||
enableLinesSelection = true) { | |||||
await import(/* webpackChunkName: "highlightjs" */ 'utils/highlightjs'); | await import(/* webpackChunkName: "highlightjs" */ 'utils/highlightjs'); | ||||
// function to highlight lines based on a url fragment | // function to highlight lines based on a url fragment | ||||
// in the form '#Lx' or '#Lx-Ly' | // in the form '#Lx' or '#Lx-Ly' | ||||
function parseUrlFragmentForLinesToHighlight() { | function parseUrlFragmentForLinesToHighlight() { | ||||
const lines = []; | const lines = []; | ||||
const linesRegexp = new RegExp(/L(\d+)/g); | const linesRegexp = new RegExp(/L(\d+)/g); | ||||
let line = linesRegexp.exec(window.location.hash); | let line = linesRegexp.exec(window.location.hash); | ||||
if (line === null) { | if (line === null) { | ||||
return; | return; | ||||
} | } | ||||
while (line) { | while (line) { | ||||
lines.push(parseInt(line[1])); | lines.push(parseInt(line[1])); | ||||
line = linesRegexp.exec(window.location.hash); | line = linesRegexp.exec(window.location.hash); | ||||
} | } | ||||
resetHighlightedLines(); | resetHighlightedLines(); | ||||
if (lines.length === 1) { | if (lines.length === 1) { | ||||
firstHighlightedLine = parseInt(lines[0]); | firstHighlightedLine = parseInt(lines[0]); | ||||
scrollToLine(highlightLine(lines[0])); | scrollToLine(highlightLine(lines[0])); | ||||
} else if (lines[0] < lines[lines.length - 1]) { | } else if (lines[0] < lines[lines.length - 1]) { | ||||
firstHighlightedLine = parseInt(lines[0]); | firstHighlightedLine = parseInt(lines[0]); | ||||
scrollToLine(highlightLine(lines[0])); | scrollToLine(highlightLine(lines[0])); | ||||
for (let i = lines[0] + 1; i <= lines[lines.length - 1]; ++i) { | highlightLines(lines[0] + 1, lines[lines.length - 1]); | ||||
highlightLine(i); | |||||
} | |||||
} | } | ||||
} | } | ||||
$(document).ready(() => { | $(document).ready(() => { | ||||
// highlight code and add line numbers | // highlight code and add line numbers | ||||
$(selector).each((i, elt) => { | $(selector).each((i, elt) => { | ||||
hljs.highlightElement(elt); | hljs.highlightElement(elt); | ||||
if (showLineNumbers) { | if (showLineNumbers) { | ||||
hljs.lineNumbersElement(elt, {singleLine: true}); | hljs.lineNumbersElement(elt, {singleLine: true}); | ||||
} | } | ||||
}); | }); | ||||
if (!showLineNumbers) { | if (!showLineNumbers || !enableLinesSelection) { | ||||
return; | return; | ||||
} | } | ||||
// click handler to dynamically highlight line(s) | // click handler to dynamically highlight line(s) | ||||
// when the user clicks on a line number (lines range | // when the user clicks on a line number (lines range | ||||
// can also be highlighted while holding the shift key) | // can also be highlighted while holding the shift key) | ||||
$('.swh-content').click(evt => { | $('.swh-content').click(evt => { | ||||
if (evt.target.classList.contains('hljs-ln-n')) { | if (evt.target.classList.contains('hljs-ln-n')) { | ||||
const line = parseInt($(evt.target).data('line-number')); | const line = parseInt($(evt.target).data('line-number')); | ||||
if (evt.shiftKey && firstHighlightedLine && line > firstHighlightedLine) { | if (evt.shiftKey && firstHighlightedLine && line > firstHighlightedLine) { | ||||
const firstLine = firstHighlightedLine; | const firstLine = firstHighlightedLine; | ||||
resetHighlightedLines(); | resetHighlightedLines(); | ||||
for (let i = firstLine; i <= line; ++i) { | highlightLines(firstLine, line); | ||||
highlightLine(i); | |||||
} | |||||
firstHighlightedLine = firstLine; | firstHighlightedLine = firstLine; | ||||
window.location.hash = `#L${firstLine}-L${line}`; | window.location.hash = `#L${firstLine}-L${line}`; | ||||
} else { | } else { | ||||
resetHighlightedLines(); | resetHighlightedLines(); | ||||
highlightLine(line); | highlightLine(line); | ||||
window.location.hash = `#L${line}`; | window.location.hash = `#L${line}`; | ||||
scrollToLine(evt.target); | scrollToLine(evt.target); | ||||
} | } | ||||
Show All 16 Lines |