From e1a747987fcab162ee1481047bada1160b88547a Mon Sep 17 00:00:00 2001 From: Siddharth VP Date: Sat, 12 Oct 2024 21:40:56 +0530 Subject: [PATCH] links: show links in live previews and preserve fragments in links * Use wikipage.content hook event so that links are also applied on content added through JS tools like live preview, real time preview, DiscussionTools, etc. (Consider checking the diff with whitespaces ignored.) * Preserve fragments (anchors) in links by using mw.Title getUrl(). Bug: T368166 Change-Id: Ib3a4d03abf7401c39bc3261ca2056cce482edb13 --- modules/pygments.links.js | 15 +++-- modules/pygments.links.scribunto.js | 87 +++++++++++++++-------------- 2 files changed, 53 insertions(+), 49 deletions(-) diff --git a/modules/pygments.links.js b/modules/pygments.links.js index 9d833b2e..96bf66f9 100644 --- a/modules/pygments.links.js +++ b/modules/pygments.links.js @@ -43,7 +43,7 @@ $( () => { title = mw.Title.newFromText( pageName, 10 ); } if ( title ) { - link.href = mw.util.getUrl( title.toText() ); + link.href = title.getUrl(); link.title = title.toText(); } if ( link.href ) { @@ -61,12 +61,15 @@ $( () => { } const commentClasses = [ 'c', 'c1', 'cm' ]; - Array.from( document.getElementsByClassName( 'mw-highlight' ) ).forEach( ( codeBlock ) => { - commentClasses.forEach( ( commentClass ) => { - Array.from( codeBlock.getElementsByClassName( commentClass ) ).forEach( ( node ) => { - processComment( node.firstChild, node ); + + mw.hook( 'wikipage.content' ).add( ( $content ) => { + $content.find( '.mw-highlight' ).get().forEach( ( codeBlock ) => { + commentClasses.forEach( ( commentClass ) => { + Array.from( codeBlock.getElementsByClassName( commentClass ) ).forEach( ( node ) => { + processComment( node.firstChild, node ); + } ); } ); } ); - } ); + } ); } ); diff --git a/modules/pygments.links.scribunto.js b/modules/pygments.links.scribunto.js index 19569c4c..3280c03a 100644 --- a/modules/pygments.links.scribunto.js +++ b/modules/pygments.links.scribunto.js @@ -1,12 +1,8 @@ $( () => { - - const classes = { - singleQuoteString: 's1', doubleQuoteString: 's2' - }; - - function addLink( element, page ) { + function addLink( element, title ) { const link = document.createElement( 'a' ); - link.href = mw.util.getUrl( page ); + link.href = title.getUrl(); + link.title = title.toText(); // put text node from element inside link const firstChild = element.firstChild; if ( !( firstChild instanceof Text ) ) { @@ -23,45 +19,50 @@ $( () => { 'mw.loadJsonData': () => true }; - const stringNodes = Array.from( document.getElementsByClassName( classes.singleQuoteString ) ) - .concat( Array.from( document.getElementsByClassName( classes.doubleQuoteString ) ) ); + mw.hook( 'wikipage.content' ).add( ( $content ) => { - stringNodes.forEach( ( node ) => { - if ( !node.nextElementSibling || - !node.nextElementSibling.firstChild || - !node.nextElementSibling.firstChild.nodeValue || - node.nextElementSibling.firstChild.nodeValue.indexOf( ')' ) !== 0 ) { - return; - } - if ( !node.previousElementSibling || !node.previousElementSibling.firstChild || - node.previousElementSibling.firstChild.nodeValue !== '(' ) { - return; - } - Object.keys( parametersToLink ).forEach( ( invocation ) => { - const parts = invocation.split( '.' ); - let partIdx = parts.length - 1; - let curNode = node.previousElementSibling && node.previousElementSibling.previousElementSibling; - while ( partIdx >= 0 ) { - if ( !curNode || curNode.firstChild.nodeValue !== parts[ partIdx ] ) { - return; - } - if ( partIdx === 0 ) { - break; - } - const prev = curNode.previousElementSibling; - if ( !prev || prev.firstChild.nodeValue !== '.' ) { - return; - } - curNode = prev.previousElementSibling; - partIdx--; + // s1 is the class applied by Pygments to single-quoted strings + // s2 is the class applied by Pygments to double-quoted strings + const stringNodes = $content.find( '.s1' ).get() + .concat( $content.find( '.s2' ).get() ); + + stringNodes.forEach( ( node ) => { + if ( !node.nextElementSibling || + !node.nextElementSibling.firstChild || + !node.nextElementSibling.firstChild.nodeValue || + node.nextElementSibling.firstChild.nodeValue.indexOf( ')' ) !== 0 ) { + return; } - const page = node.firstChild.nodeValue.slice( 1, -1 ); - const condition = parametersToLink[ invocation ]; - const title = mw.Title.newFromText( page ); - if ( title && condition( title ) ) { - addLink( node, title.toText() ); + if ( !node.previousElementSibling || !node.previousElementSibling.firstChild || + node.previousElementSibling.firstChild.nodeValue !== '(' ) { + return; } + Object.keys( parametersToLink ).forEach( ( invocation ) => { + const parts = invocation.split( '.' ); + let partIdx = parts.length - 1; + let curNode = node.previousElementSibling && node.previousElementSibling.previousElementSibling; + while ( partIdx >= 0 ) { + if ( !curNode || curNode.firstChild.nodeValue !== parts[ partIdx ] ) { + return; + } + if ( partIdx === 0 ) { + break; + } + const prev = curNode.previousElementSibling; + if ( !prev || prev.firstChild.nodeValue !== '.' ) { + return; + } + curNode = prev.previousElementSibling; + partIdx--; + } + const page = node.firstChild.nodeValue.slice( 1, -1 ); + const condition = parametersToLink[ invocation ]; + const title = mw.Title.newFromText( page ); + if ( title && condition( title ) ) { + addLink( node, title ); + } + } ); } ); - } ); + } ); } );