mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/SyntaxHighlight_GeSHi
synced 2024-11-23 22:13:40 +00:00
d6cc861de7
Change-Id: I224de2d2d72525b61608d7b6d0f13ce84a699ef7
116 lines
3 KiB
JavaScript
116 lines
3 KiB
JavaScript
$( function () {
|
|
|
|
/**
|
|
* Parse a line ID, e.g. "L-18"
|
|
*
|
|
* @param {string} id Line ID fragment
|
|
* @return {Object} Object with a string prefix and number
|
|
*/
|
|
function parseId( id ) {
|
|
const matches = id.match( /(.*)-([0-9]+)/ );
|
|
return {
|
|
prefix: matches[ 1 ],
|
|
number: +matches[ 2 ]
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Build a line ID from a parsed ID
|
|
*
|
|
* @param {Object} parsedId See #parseId
|
|
* @return {string} ID fragment
|
|
*/
|
|
function buildId( parsedId ) {
|
|
return parsedId.prefix + '-' + parsedId.number;
|
|
}
|
|
|
|
/**
|
|
* Get a line element from an ID
|
|
*
|
|
* @param {string} id ID
|
|
* @return {HTMLElement|null} Line element, or null if not found (or the element is not a line)
|
|
*/
|
|
function getLineElement( id ) {
|
|
const line = mw.util.getTargetFromFragment( id );
|
|
// Support IE 11, Edge 14, Safari 7: Can't use unprefixed Element.matches('… *') yet.
|
|
if ( !$( line ).closest( '.mw-highlight' ).length ) {
|
|
// Element not in a highlight block
|
|
return null;
|
|
}
|
|
return line;
|
|
}
|
|
|
|
let lastLines, lastAnchorLine;
|
|
|
|
/**
|
|
* Handle hash change events
|
|
*
|
|
* @param {boolean} scrollIntoView Scroll the selected lines into view
|
|
*/
|
|
function onHashChange( scrollIntoView ) {
|
|
const hash = location.hash.slice( 1 );
|
|
|
|
const lines = [];
|
|
let anchorLine, focusLine;
|
|
const parts = hash.split( '--' );
|
|
if ( parts.length === 2 ) {
|
|
anchorLine = getLineElement( parts[ 0 ] );
|
|
focusLine = getLineElement( parts[ 1 ] );
|
|
if ( anchorLine && focusLine ) {
|
|
const anchorId = parseId( parts[ 0 ] );
|
|
const focusId = parseId( parts[ 1 ] );
|
|
if ( anchorId.prefix === focusId.prefix ) {
|
|
for ( let i = Math.min( anchorId.number, focusId.number ); i <= Math.max( anchorId.number, focusId.number ); i++ ) {
|
|
lines.push( mw.util.getTargetFromFragment( buildId( { prefix: anchorId.prefix, number: i } ) ) );
|
|
}
|
|
if ( scrollIntoView ) {
|
|
// A line range will not automatically scroll into view
|
|
lines[ 0 ].scrollIntoView();
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
anchorLine = getLineElement();
|
|
if ( anchorLine ) {
|
|
lines.push( anchorLine );
|
|
}
|
|
}
|
|
|
|
lastAnchorLine = anchorLine;
|
|
|
|
if ( lastLines ) {
|
|
lastLines.forEach( ( line ) => line.classList.remove( 'hll' ) );
|
|
}
|
|
lines.forEach( ( line ) => line.classList.add( 'hll' ) );
|
|
|
|
lastLines = lines;
|
|
}
|
|
|
|
window.addEventListener( 'hashchange', onHashChange );
|
|
|
|
$( document.body ).on( 'click', '.mw-highlight .linenos', ( e ) => {
|
|
e.preventDefault();
|
|
|
|
const targetUrl = new URL( e.target.parentNode.href );
|
|
|
|
if ( e.shiftKey && lastAnchorLine ) {
|
|
const anchorId = parseId( lastAnchorLine.getAttribute( 'id' ) );
|
|
const focusId = parseId( targetUrl.hash.slice( 1 ) );
|
|
if ( anchorId.prefix === focusId.prefix ) {
|
|
const hash = buildId( anchorId ) + '--' + buildId( focusId );
|
|
history.replaceState( null, '', '#' + hash );
|
|
} else {
|
|
history.replaceState( null, '', targetUrl );
|
|
}
|
|
} else {
|
|
history.replaceState( null, '', targetUrl );
|
|
}
|
|
|
|
onHashChange();
|
|
} );
|
|
|
|
// Check hash on load
|
|
onHashChange( true );
|
|
|
|
}() );
|