Jump to content

User:Itcouldbepossible/copy-section-2.0.js

From Wikipedia, the free encyclopedia
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 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>