User:Enterprisey/req-helper.js

//<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>