Jump to content

User:Enterprisey/req-helper.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.
//<nowiki>
( function ( $, mw ) {
    if ( mw.config.get( 'wgAction' ) === 'view' &&
         mw.config.get( 'wgPageName' ).indexOf('Wikipedia:Requested_articles') === 0 &&
         mw.config.get( 'wgPageName' ) !== "Wikipedia:Requested_articles" &&
         !$( "#mw-diff-ntitle1" ).length &&
         !$( "#mw-revision-info" ).length ) {
        
        // Load and display form
        mw.loader.using( [ "mediawiki.api", "mediawiki.util" ] ).then( function () {
            $.getJSON(
                mw.util.wikiScript('api'),
                {
                    format: 'json',
                    action: 'query',
                    prop: 'revisions',
                    rvprop: 'content',
                    rvlimit: 1,
                    titles: "User:Enterprisey/req-helper.js/tpl-panel.js"
                }
            ).done( function ( data ) {
                var pageId = Object.keys(data.query.pages)[0];
                var panelHtml = data.query.pages[pageId].revisions[0]['*'];
                $( "#jump-to-nav" ).after( panelHtml );
                
                $( "#req-helper-panel input.view-option" ).click( updateRequestActions );
                $( "#req-helper-panel input[type='radio']" ).click( updateRequestDisplay );
                
                // Enable save button if there are requests marked for deletion
                $( "#mw-content-text" ).on( "click", "a.delete-action", updateSaveChangesButton );
                
                // Save handler
                $( "#save-changes" ).click( function ( event ) {
                    $( "#save-changes" ).prop( "disabled", true );
                    editPage( function ( wikitext ) {
                        $( ".marked-for-deletion" ).each( function ( index, element ) {
                            var pageTitle = $( element ).children( "a" ).first().text();
                            wikitext = removeRequest( wikitext, pageTitle );
                        } );
                        return wikitext;
                    } );
                } ); // end save handler
                
                // Mark blue handler
                $( "#mark-bluelinks" ).click( function ( event ) {
                    forEachRequest( function ( element ) {
                        
                        var elemClass = $( element ).attr( "class" );
                        if( $( "#also-mark-redirects" ).is( ":checked" ) ) {
                            if( elemClass !== "mw-redirect" && elemClass ) return;
                        } else {
                            if( elemClass ) return;
                        }
                        
                        if( !$( element ).parent().hasClass( "marked-for-deletion" ) ) {
                            $( element ).parent().addClass( "marked-for-deletion" );
                        }

                        // Ensure that the text of the action link is correct
                        if( $( element ).parent().hasClass( "marked-for-deletion" ) ) {
                            $( element ).parent().find( ".delete-action" ).text( "undelete" );
                        }
                    } );
                    updateSaveChangesButton();
                } ); // end mark handler
                
                // Create action links, initially hidden
                forEachRequest( function ( link ) {
                    $( "<span>" )
                        .insertAfter( link )
                        .addClass( "request-actions" )
                        .css( "margin-left", "0.25em" )
                        .append( $( "<span>", { "text": "( ", "class": "action-parenthesis" } ) )
                        .append( $( "<a>" )
                            .text( "search" )
                            .addClass( "search-action" )
                            .attr( "href", "https://www.google.com/search?q=" + $( link ).text().replace( / /, "+" ) ) )
                        .append( $( "<span>", { "text": " | ", "class": "action-separator" } ) )
                        .append( $( "<a>" )
                            .text( "delete" )
                            .addClass( "delete-action" )
                            .click( function ( e ) {
                                $( link ).parent().toggleClass( "marked-for-deletion" );
                                if( $( this ).text() === "delete" ) {
                                    $( this ).text( "undelete" );
                                } else {
                                    $( this ).text( "delete" );
                                }
                            } ) )
                        .append( $( "<span>", { "text": " )", "class": "action-parenthesis" } ) );
                } ); // end action link creation loop
                
                // Make a style element to be used by updateRequestActions
                $( "#req-helper-panel" ).append( $( "<style>", { "id": "visibility-css" } ) );
                updateRequestActions();
                
                updatePageIssues();
            } ); // end form-loaded handler
        } ); // end mw.loader.using handler
    } // end initial if block

    /**
     * Removes a request with the given page title from the given wikitext.
     * @returns The wikitext, with the specified request removed.
     */
    function removeRequest ( wikitext, pageTitle ) {

        // Sanitize the page title so we can put it in a regex
        // (regex from http://stackoverflow.com/a/3561711)
        pageTitle = pageTitle.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');

        [
            "\\*\\s?\\[\\[" + pageTitle + "\\]\\].*?\n",
            "\\*\\s?\\{\\{req\\|" + pageTitle + "\\}\\}.*?\n"
        ].forEach( function ( regex ) {
            regex = new RegExp( regex, "i" );
            wikitext = wikitext.replace( regex, "" );
        } );
        return wikitext;
    }
    
    function updateSaveChangesButton () {
        var numMarkedRequests = $( ".marked-for-deletion" ).length;
        $( "#save-changes" ).prop( "disabled", numMarkedRequests === 0 );
        $( "#save-changes" ).text( numMarkedRequests ? ( "Delete " + numMarkedRequests + " request" + ( ( numMarkedRequests === 1 ) ? "" : "s" ) ) : "Save changes" );
    }
    
    // Takes a callback that takes a *link* object
    function forEachRequest ( callback ) {

        // Precompute a list of navboxes
        var navboxes = arrayFromNodeList( document.getElementsByClassName( "navbox" ) );
        var links = arrayFromNodeList( document.querySelectorAll( "#mw-content-text a" ) );

        for( var i = 0; i < links.length; i++ ) {
            var element = links[i];
            
            // Test to make sure it's an actual request
            if( navboxes.some( function ( navbox ) { return $.contains( navbox, element ); } ) ) continue;
            if( $( element ).children( ".tocnumber" ).length ) continue;
            if( $( element ).parent().prop( "tagName" ) !== "LI" ) continue;
            if( $( element ).parents( "#toc" ).length ) continue;
            if( $( element ).parent().children( "a" ).first().text() !== $( element ).text() ) continue;
            
            // Run callback
            callback( element );
        }
    }
    
    function updateRequestDisplay () {
        var noSourcesAction = $( "input[name=no-sources]:checked" ).val(),
            someSourcesAction = $( "input[name=some-sources]:checked" ).val();
        forEachRequest( function ( link ) {
            // Highlight articles based on # of provided refs
            var listElement = $( link ).parent();
            if( listElement.children( ".external" ).length === 0 ) {
                if( noSourcesAction === "hide" ) {
                    listElement.hide();
                } else {
                    listElement.show();
                    listElement.css( "background-color",  ( $( "input[name=no-sources]:checked" ).val() === "highlight" ) ? "#FEE" : "#FFF" );
                }
            } else {
                if( someSourcesAction === "hide" ) {
                    listElement.hide();
                } else {
                    listElement.show();
                    listElement.css( "background-color",  ( $( "input[name=some-sources]:checked" ).val() === "highlight" ) ? "#EFE" : "#FFF" );
                }
            }
        } );
    }
    
    function updateRequestActions () {
        var showSearch = $( "#show-search-option" ).is( ":checked" ),
            showDelete = $( "#show-delete-option" ).is( ":checked" );
            
        // Make sure we aren't destroying any deletion state
        if( !showDelete && $( ".marked-for-deletion" ).length !== 0 ) {
            if( window.confirm( "You've marked some requests for deletion. " +
				"Are you sure you want to exit mark-for-deletion mode without deleting the requests?" ) ) {
                
                // Wipe deletion state
                $( "a.delete-action" ).text( "delete" );
                $( "li.marked-for-deletion" ).toggleClass( "marked-for-deletion" );
                $( "#save-changes" ).prop( "disabled", true );
            } else {
                
                // The user is indecisive; get out
                $( "#show-delete-option" ).prop( "checked", true );
                return;
            }
        }
        
        var newVisibilityCss = "";
        if( !showSearch && !showDelete ) newVisibilityCss += "span.action-parenthesis{display:none;}";
        if( !showSearch ) newVisibilityCss += "a.search-action{display:none;}";
        if( !showDelete ) newVisibilityCss += "a.delete-action{display:none;}";
        if( !showSearch || !showDelete ) newVisibilityCss += "span.action-separator{display:none;}";
        $( "#visibility-css" ).html( newVisibilityCss );
    }
    
    function updatePageIssues () {
    	$( "#page-issues" ).empty().append( "<ul></ul>" );
    	var addIssue = function ( issue ) { return $( "<li>" ).html( issue ).appendTo( "#page-issues ul" ); };
        $.getJSON(
            mw.util.wikiScript('api'),
            {
                format: 'json',
                action: 'query',
                prop: 'revisions',
                rvprop: 'content',
                rvlimit: 1,
                titles: mw.config.get( 'wgPageName' )
            }
        ).done( function ( data ) {
            var pageId = Object.keys(data.query.pages)[0];
            var wikitext = data.query.pages[pageId].revisions[0]['*'];
            
            // Regex counter from http://stackoverflow.com/a/4009768
            var refs = ( wikitext.match( /<ref>/g ) || [] ).length;
            if( refs ) {
                addIssue( refs + " &lt;ref&gt; tag" + ( ( refs === 1 ) ? "" : "s" ) );
            }
            
            var noLinkReqs = [];
            forEachRequest( function ( element ) {
            	if( [ "<a ", "<i>" ].indexOf( $( element ).parent().html().substring( 0, 3 ) ) === -1 ) {
            	    //console.log( [ "<a>", "<i>" ].indexOf( $( element ).parent().html().substring( 0, 3 ) ) + ", " + $( element ).parent().html().substring( 0, 3 ) );
            		noLinkReqs.push( $( element ).parent().html() );
            	}
            } );
            if( noLinkReqs.length ) {
                addIssue( noLinkReqs.length + " req" + ( ( noLinkReqs.length === 1 ) ? "" : "s" ) + " without a link" )
                    .append( $( "<a>", { "text": "(highlight)", "role": "button", "style": "margin-left: 0.75ch" } )
                        .click( function ( event ) {
                            forEachRequest( function ( element ) {
                                if( noLinkReqs.indexOf( $( element ).parent().html() ) !== -1 ) {
                                	$( element ).parent().css( "background-color", "#FCC" );
                                }
                            } );
                            $( this ).remove();
                        } ) );
            }
            
            var timestamps = ( wikitext.match( /\(UTC\)/g ) || [] ).length;
            if( timestamps ) {
            	addIssue( timestamps + " timestamp" + ( ( timestamps === 1 ) ? "" : "s" ) );
            }
            
            // Set state overall
            if( $( "#page-issues ul li").length ) {
                $( "#page-issues" ).css( "background-color", "#FEE" );
            } else {
                $( "#page-issues" ).css( { "vertical-align": "center",
                                           "text-align": "center" } );
                $( "#page-issues" ).css( "background-color", "#EFE" );
                $( "#page-issues" ).text( "(no issues)" );
            }
        } ); // End get-page-wikitext handler
    }
    
    function editPage ( processWikitext ) {
        $( "#req-helper-panel table").append( "<tr><td colspan=5><ul id='req-status'></ul></td></tr>" );
        var status = function ( newStatus ) { return $( "<li> ").appendTo( "#req-helper-panel ul#req-status" ).text( newStatus ); };

        status( $( ".marked-for-deletion" ).length + " item(s) to delete." );

        var wikitext;
        var getTextStatus = status( "Getting wikitext..." );
        $.getJSON(
            mw.util.wikiScript('api'),
            {
                format: 'json',
                action: 'query',
                prop: 'revisions',
                rvprop: 'content',
                rvlimit: 1,
                titles: mw.config.get( 'wgPageName' )
            }
        ).done( function ( data ) {
            var pageId = Object.keys(data.query.pages)[0];
            var wikitext = data.query.pages[pageId].revisions[0]['*'];
            getTextStatus.text( "Got wikitext." );
            wikitext = processWikitext( wikitext );
            status( "Processed wikitext." );
            var saveStatus = status( "Saving page..." );
            var plural = ( $( ".marked-for-deletion" ).length === 1 ) ? "" : "s";
            ( new mw.Api() ).postWithEditToken( {
                action: "edit",
                title: mw.config.get( 'wgPageName' ),
                summary: "Removing " + $( ".marked-for-deletion" ).length + " request" + plural + " ([[User:APerson/req-helper|req-helper]])",
                text: wikitext
            } ).done ( function ( data ) {
                if( data && data.edit && data.edit.result && data.edit.result == 'Success' ) {
                    saveStatus.html( "<b>Saved page!</b> (" )
                        .append( $( "<a>" )
                            .text( "reload" )
                            .attr( "href", "#" )
                            .click( function () { document.location.reload( true ); } ) )
                        .append( ")" );
                } else {
                    saveStatus.text( "There was an error saving the page." );
                    console.log( "Page save result: " + JSON.stringify( data ) );
                }
            } );
        } ); // end get-current-page-wikitext handler
    }

    // Silly utility function, from https://stackoverflow.com/a/5242912/1757964
    function arrayFromNodeList( nl ) {
        var arr = [];
        for ( var i = 0, ref = arr.length = nl.length; i < ref; i++ ) {
            arr[i] = nl[i];
        }
        return arr;
    }
}( jQuery, mediaWiki ) );
//</nowiki>