Jump to content

User:Enterprisey/copy-section-link.js

From Wikipedia, the free encyclopedia
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
// Fixed version of [[User:Enterprisey/copy-section-link.js]]
// <nowiki>
$.when(
    $.ready,
    mw.loader.using( [ "mediawiki.util", "oojs-ui-core", "oojs-ui-widgets" ] )
).then( function () {
	/*
	 * The convoluted function is needed, because there are different HTML
	 * layouts for "headings" in different skins.
	 * In Vector 2022, layout of ==Second level== versus ===Third level===
	 * headings is different even for a _single_ skin.
	 *
	 * The HTML layout is either
	 *    <div><h*></h*><edit section link /></div>
	 * or
	 *    <h*><edit section link /></h*>
	 *
	 * For details, see:
	 *   - https://www.mediawiki.org/w/index.php?title=Heading_HTML_changes&oldid=6538029
	 */
	// Returns a plain HTMLElement
	function findEditSectionForHeader(header) {
		// in Vector, the bracketed [edit] section link is a direct child element/node
		const maybeVectorEditSection = header.querySelector('.mw-editsection');
		if (maybeVectorEditSection) {
			return maybeVectorEditSection;
		}
		// in other skins, the bracketed [edit] section link is a sibling of <h2> <h3> etc
		if (header.parentElement.classList.contains('mw-heading')) {
			const maybeEditSection = header.parentElement.querySelector('.mw-editsection');
			if (maybeEditSection) {
				return maybeEditSection;
			}
		}
		return null;
	}
	/*
	 * The search for all section headings starts with
	 * finding all <h*> tags, which aren't for the table of contents.
	 * From the <h*> tags, we find the "[edit] section links".
	 */
	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);
        	console.warn('[copy-section-link]', 'edit section link not found:', target);
        } else {
        	target = $(editSection);
        }
        target.after($( "<a>", { "class": "copy-section-link-pilcrow" } )
                .text( "¶" )
                .click( function () {
                    if( popup === null ) {
                        const hash = header.id ? header.id : header.querySelector('.mw-headline')?.id;
                        var oldid = mw.util.getParamValue( "oldid" );
                        var popupContent;
                        function makeContent( pageName, id ) {
                            var wikitext = (pageName + "#" + hash).replace( /_/g, " " );
                            if( !window.copySectionLinkNoSquareBrackets ) {
                               wikitext = '[[' + wikitext + ']]';
                            }
                            return $( '<p>', { "class": "copy-section-link-content" } ).append(
                                $( "<code>", { "id": "copy-section-wikilink" + id } ).text( wikitext ),
                                $( "<button>" )
                                    .text( "Copy" )
                                    .css( { "padding": "0.5em", "cursor": "pointer", "margin-left": "0.5em" } )
                                    .click( function () {
                                        var textField = $( this ).prev();
                                        try {
                                            navigator.clipboard.writeText( textField.text() );
                                        } catch( e ) {
                                            textField.select();
                                            document.execCommand( "copy" );
                                        }
                                    } ),
                                $( "<br>" ),
                                $( "<a>" )
                                	.attr( "href", mw.util.getUrl( pageName ) + "#" + encodeURIComponent( hash ) )
                                	.text( "external" )
                            );
                        }

                        var generalCss = { 'font-size': '0.9rem', 'font-family': 'sans-serif' };

                        var index;
                        if( oldid ) {
                            popupContent = makeContent( "Special:Permalink/" + oldid );
                            popupContent.css( generalCss );
                            popupContent.css( { 'padding-top': '0.5em', 'font-weight': 'normal' } );
                        } else {
                            var normalPanel = new OO.ui.TabPanelLayout( 'normal', {
                                label: 'Link',
                                $content: makeContent( mw.config.get( 'wgPageName' ), 'normal' )
                            } );
                            var permalinkPanel = new OO.ui.TabPanelLayout( 'permalink', {
                                label: 'Permalink',
                                $content: makeContent( 'Special:Permalink/' + mw.config.get( 'wgCurRevisionId' ), 'permalink' )
                            } );
                            index = new OO.ui.IndexLayout();
                            index.addTabPanels( [ normalPanel, permalinkPanel ] );
                            popupContent = index.$element;
                        }
                        popup = new OO.ui.PopupWidget( {
                            $content: popupContent,
                            $floatableContainer: $( this ),
                            padded: true,
                            width: 400,
                            height: 190,
                            align: 'forwards',
                        } );
                        $( this ).after( popup.$element );
                        if( index ) {
                            index.$menu.find( 'span.oo-ui-labelElement-label' ).css( generalCss );
                            index.$content.css( generalCss );
                        }

                        popup.toggle( true );
                    } else {
                        popup.toggle();
                    }
                } ) );
    } );
    mw.util.addCSS( ".mw-heading .copy-section-link-pilcrow" +
                        "{ display: none; margin-left: 1em; }" +
                    ".mw-heading:hover .copy-section-link-pilcrow" +
                        "{ display: inline; }" +
                    ".mw-heading .copy-section-link-pilcrow + .oo-ui-widget" +
                        "{ font-weight: normal; }" );
} );
// </nowiki>