User:Itcouldbepossible/copy-section-2.0.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump.
This code will be executed when previewing this page.
This code will be executed when previewing this page.
Documentation for this user script can be added at User:Itcouldbepossible/copy-section-2.0.
// Fixed and upgraded version of [[User:Enterprisey/copy-section-link.js]]
// <nowiki>
$.when(
$.ready,
mw.loader.using( [ "mediawiki.util", "oojs-ui-core", "oojs-ui-widgets" ] )
).then( function () {
/*
* HTML layout differences handler for different skins (Vector 2022 etc.)
*/
function findEditSectionForHeader(header) {
const maybeVectorEditSection = header.querySelector('.mw-editsection');
if (maybeVectorEditSection) return maybeVectorEditSection;
if (header.parentElement.classList.contains('mw-heading')) {
const maybeEditSection = header.parentElement.querySelector('.mw-editsection');
if (maybeEditSection) return maybeEditSection;
}
return null;
}
const allHeaders = $("#mw-content-text .mw-parser-output").find(":header").filter(':not(#mw-toc-heading)');
allHeaders.each( function(i, header) {
var popup = null;
var editSection = findEditSectionForHeader(header);
let target;
if (editSection === null) {
target = $(header);
} else {
target = $(editSection);
}
target.after($( "<a>", { "class": "copy-section-link-pilcrow", "href": "javascript:void(0);" } )
.text( "¶" )
.click( function ( e ) {
e.preventDefault();
var $pilcrow = $( this );
if( popup === null ) {
const hash = header.id ? header.id : header.querySelector('.mw-headline')?.id;
var popupContent;
// Upgraded UI Builder for the popup rows (handles Normal, Permalink, and Diff)
function makeContent( baseText, linkType, baseUrl ) {
var container = $('<div>', { "class": "copy-section-link-content", "style": "padding-top: 0.5em;" });
var hashText = hash ? "#" + hash.replace(/_/g, " ") : "";
var fullWikitext = baseText.replace(/_/g, " ") + hashText;
var absoluteUrl = baseUrl + (hash ? "#" + encodeURIComponent(hash) : "");
// Helper function to create a labeled copy row
function addRow(label, textToCopy) {
var row = $('<div style="margin-bottom: 0.6em; display: flex; align-items: center;">').append(
$('<span style="min-width: 130px; font-weight: bold; font-size: 0.9em; font-family: sans-serif;">').text(label + ":"),
$('<input>', {
type: 'text',
readonly: true,
value: textToCopy,
style: "flex-grow: 1; margin: 0 0.5em; padding: 0.3em; border: 1px solid #ccc; border-radius: 2px; font-family: monospace; font-size: 0.9em;"
}),
$("<button>")
.text( "Copy" )
.css( { "cursor": "pointer", "padding": "0.3em 0.6em", "font-size": "0.9em" } )
.click( function () {
var inputField = $( this ).prev()[0];
inputField.select();
try {
navigator.clipboard.writeText( inputField.value );
} catch( e ) {
document.execCommand( "copy" );
}
} )
);
container.append(row);
}
if (linkType === 'normal') {
addRow("Page", baseText.replace(/_/g, " "));
addRow("Wikitext", "[[" + fullWikitext + "]]");
addRow("Page with section", fullWikitext);
addRow("URL", absoluteUrl);
} else {
// For Permalinks and Diffs, skip the raw "Page" title row
addRow("Wikitext", "[[" + fullWikitext + "]]");
addRow("Page with section", fullWikitext);
addRow("URL", absoluteUrl);
}
return container;
}
var panels = [];
// 1. Normal Panel
var normalUrl = window.location.origin + mw.util.getUrl( mw.config.get('wgPageName') );
var normalPanel = new OO.ui.TabPanelLayout( 'normal', {
label: 'Link',
$content: makeContent( mw.config.get( 'wgPageName' ), 'normal', normalUrl )
} );
panels.push( normalPanel );
// 2. Permalink Panel
var currentRevId = mw.config.get( 'wgRevisionId' ) || mw.config.get( 'wgCurRevisionId' );
var permalinkBaseText = 'Special:Permalink/' + currentRevId;
var permalinkUrl = window.location.origin + mw.util.getUrl( permalinkBaseText );
var permalinkPanel = new OO.ui.TabPanelLayout( 'permalink', {
label: 'Permalink',
$content: makeContent( permalinkBaseText, 'permalink', permalinkUrl )
} );
panels.push( permalinkPanel );
// 3. Diff Panel (Dynamically added ONLY if on a diff page)
var wgDiffNewId = mw.config.get('wgDiffNewId');
var wgDiffOldId = mw.config.get('wgDiffOldId');
if ( wgDiffNewId ) {
var diffBaseText = wgDiffOldId ? ('Special:Diff/' + wgDiffOldId + '/' + wgDiffNewId) : ('Special:Diff/' + wgDiffNewId);
var diffUrl = window.location.origin + mw.util.wikiScript('index') +
"?title=" + encodeURIComponent(mw.config.get('wgPageName')) +
"&diff=" + wgDiffNewId;
if ( wgDiffOldId ) {
diffUrl += "&oldid=" + wgDiffOldId;
}
var diffPanel = new OO.ui.TabPanelLayout( 'diff', {
label: 'Diff',
$content: makeContent( diffBaseText, 'diff', diffUrl )
} );
panels.push( diffPanel );
}
// Apply panels to IndexLayout
var index = new OO.ui.IndexLayout();
index.addTabPanels( panels );
popupContent = index.$element;
popup = new OO.ui.PopupWidget( {
$content: popupContent,
$floatableContainer: $pilcrow,
$autoCloseIgnore: $pilcrow,
padded: true,
width: 550, // Slightly wider to accommodate long diff URLs
height: 270,
align: 'forwards',
autoClose: true
} );
$( document.body ).append( popup.$element );
// Close popup on scroll
var scrollHandler = function() {
if ( popup.isVisible() ) {
popup.toggle( false );
}
};
popup.on( 'toggle', function ( visible ) {
if ( visible ) {
setTimeout( function() {
$( window ).on( 'scroll', scrollHandler );
}, 100 );
} else {
$( window ).off( 'scroll', scrollHandler );
}
} );
if( index ) {
index.$menu.find( 'span.oo-ui-labelElement-label' ).css( 'font-family', 'sans-serif' );
}
popup.toggle( true );
} else {
popup.toggle();
}
} ) );
} );
// Feature: Paragraph symbol visible all the time so stuff doesn't slide around.
mw.util.addCSS( ".mw-heading .copy-section-link-pilcrow" +
"{ display: inline-block; margin-left: 1em; opacity: 0.3; transition: opacity 0.2s; text-decoration: none; }" +
".mw-heading:hover .copy-section-link-pilcrow" +
"{ opacity: 1; }" +
".mw-heading .copy-section-link-pilcrow + .oo-ui-widget" +
"{ font-weight: normal; }" );
} );
// </nowiki>