User:Enterprisey/easy-brfa.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.
//<nowiki>
( function ( $, mw ) {
    const MAIN_BRFA_PAGE = "Wikipedia:Bots/Requests_for_approval";
    const TRIGGER_PAGE = "Wikipedia:Bots/Requests_for_approval/request";
    const TEMPLATE_PAGE = "User:Enterprisey/easy-brfa.js/tpl-form.js";

    mw.loader.load( "jquery.chosen" );
    mw.loader.load( "mediawiki.api" );
    mw.loader.load( "mediawiki.ui.input", "text/css" );
    mw.loader.load( "mediawiki.ui.button", "text/css" );

    var currPageName = mw.config.get( "wgPageName" );
    if ( currPageName === MAIN_BRFA_PAGE ) {
        $( "table.collapsible" ).first().replaceWith( "<br /><a href='//en.wikipedia.org/wiki/" + TRIGGER_PAGE + "'><span class='mw-ui-button mw-ui-progressive mw-ui-big' role='button'>Make a new request</span></a><br />" );
        return;
    } else if ( currPageName !== TRIGGER_PAGE ) {
        return;
    }

    $( "#easy-brfa-form" ).empty();
    $( "<div>" )
	.attr( "id", "loading-message" )
	.addClass( "warningbox" )
	.text( "Loading..." )
        .appendTo( "#easy-brfa-form" );

    // Load and display form
    $.getJSON(
        mw.util.wikiScript( 'api' ),
        {
            format: 'json',
            action: 'query',
            prop: 'revisions',
            rvprop: 'content',
            rvlimit: 1,
            titles: TEMPLATE_PAGE
        }
    ).done( function ( data ) {
        const MARKER = "<!-- -------------------------------------------------------- -->";
        var pageId = Object.keys(data.query.pages)[0];
        var formAndTemplate = data.query.pages[pageId].revisions[0]['*'];
        var formMarkup = formAndTemplate.substr(0, formAndTemplate.indexOf(MARKER));
        var brfaTemplate = formAndTemplate.substring(formAndTemplate.indexOf(MARKER) + MARKER.length);
        $( "#easy-brfa-form #loading-message" ).remove();
        $( "#easy-brfa-form" ).append( formMarkup );

        // Validation logic for the bot name and task number
        $( "#bot-name, #task-number" ).on( "input", function () {
            var botName = document.getElementById( "bot-name" ).value;
            var taskNum = document.getElementById( "task-number" ).value;

            // Validate bot name
            doesPageExist( "User:" + botName ).then( function ( userPageExists ) {
                $( "#bot-name-status" )
                    .removeClass( "pass fail" )
                    .addClass( userPageExists ? "pass" : "fail" )
                    .text( userPageExists ? "Bot user page exists." : "No user page exists for that bot!" );
            } );

            // Validate bot number as a number
            if( !isNormalInteger( taskNum ) ) {
                $( "#task-number-status" )
                    .removeClass( "pass fail" )
                    .addClass( "fail" )
                    .text( "Invalid task number." );
            } else {

                // Check if bot number is being used
                var title = "Wikipedia:Bots/Requests for approval/" +
                    $( "#bot-name" ).val() + ( taskNum === "1" ? "" : " " + taskNum );
                doesPageExist( title ).then( function ( brfaExists ) {
                    $( "#task-number-status" )
                        .removeClass( "pass fail" )
                        .addClass( brfaExists ? "fail" : "pass" )
                        .text( brfaExists ? "There's already a BRFA with that task number!" : "Task number valid." );
                    document.getElementById( "submit-brfa" ).disabled = !isFormReady();
                } );
            }

            document.getElementById( "submit-brfa" ).disabled = !isFormReady();
        } );

        // Validation handler for text fields
        $( "#easy-brfa-form input[type=text], #easy-brfa-form textarea" ).each( function () {
            $( this ).on( "input", function () {
                document.getElementById( "submit-brfa" ).disabled = !isFormReady();
            } );
        } );
        
        $( "#easy-brfa-form input[type=radio]" ).each( function () {
            $( this ).on( "click", function () {
                document.getElementById( "submit-brfa" ).disabled = !isFormReady();
            } );
        } );

        // Event handler
        $( "#submit-brfa" ).click( function () {
            if( !isFormReady() ) {
                $( this ).disabled = true;
                $( "<span>" )
                    .addClass( "submit-error-message" )
                    .text( "Fill out the missing form fields before you submit!" )
                    .insertAfter( $( this ) );
                return;
            }

            $( "<ul>" ).attr( "id", "status-list" ).appendTo("#easy-brfa-form" );
            $( "#submit-brfa" )
                .text( "Submitting..." )
                .prop( "disabled", true );

            // Build form data
            var formData = {};
            $( "#easy-brfa-form input[type=text], #easy-brfa-form textarea" ).each( function () {
                formData[$( this ).attr( "id" )] = $( this ).val();
            } );
            $( "#easy-brfa-form input[type=checkbox]" ).each( function () {
                formData[$( this ).attr( "id" )] = $( this ).is(':checked') ? "Yes" : "No";
            } );
            formData.operation = $('input[name=operation]:checked').val();

            // Send the requests
            $.when(
                createBrfa( brfaTemplate, formData )
            ).then( function () {
                $.when(
                    transcludeBrfa( formData["bot-name"], formData["task-number"] )
                ).then( function () {
                    showStatus("Woohoo! We're done.");
                    $( "#submit-brfa" ).text( "Submitted!" );
                } );
            } );
            } ); // end submit handler
    } ); // end form load handler

    /*
     * Is the form ready for submission?
     */
    function isFormReady() {

        // Check validated fields - any statuses marked with the fail class?
        if( document.querySelector( ".validation-status.fail" ) ) {
            return false;
        }

        // Is an operation mode selected?
        if( !document.querySelector('input[name=operation]:checked') ) {
            return false;
        }

        // Is text entered in each of the textboxes and textareas?
        var requiredTextInputIds = ["function-overview", "edit-period", "pages-affected", "function-details"];
        for( var i = 0; i < requiredTextInputIds.length; i++ ) {
            if( !document.getElementById( requiredTextInputIds[i] ).value ) {
                return false;
            }
        }

        return true;
    }

    /*
     * Returns a Deferred that resolves with a true if the given page exists
     * and a false if it doesn't.
     */
    function doesPageExist( pageTitle ) {
        var result = $.Deferred();
        $.ajax( {
            url: mw.util.wikiScript( 'api' ),
            dataType: 'json',
            data: {
                format: 'json',
                action: 'query',
                titles: pageTitle
            }
        } ).done ( function ( data ) {
            if( data && data.query && data.query.pages ) {
                result.resolve( !data.query.pages.hasOwnProperty( "-1" ) );
            }
        } );
        return result;
    }

    function showStatus( newStatus ) {
        return $( "<li>" )
            .appendTo( "#easy-brfa-form ul" )
            .html( newStatus );
    }

    /*
     * Templates in the form responses to create a BRFA, then saves it to the BRFA subpage.
     */
    function createBrfa( brfaTemplate, formData ) {
        var deferred = $.Deferred();

        const HEADER = "<noinclude>[[Category:Open Wikipedia bot requests for approval|{{subst:#invoke:BRFA|botNameNumber}}]]</noinclude>\n=={{subst:#invoke:BRFA|userpageLink}}==\n{{subst:#invoke:BRFA|newbotTemplate}}\n\n'''Operator:''' {{botop|{{subst:currentuser}}}}\n\n'''Time filed:''' {{subst:Currentdate}}\n";

        // Do the template
        var brfaText = HEADER + brfaTemplate;
        for ( var fieldName in formData ) {
                brfaText = brfaText.replace("((" + fieldName + "))", formData[fieldName]);
        }

        // Get the subpage name
        var pageTitle = "Wikipedia:Bots/Requests for approval/" +
            formData["bot-name"] +
            ( (formData["task-number"] == 1) ? "" : (" " + formData["task-number"] ) );

        // Create the BRFA
        ( new mw.Api() ).postWithEditToken( {
            action: "edit",
            title: pageTitle,
            summary: "Creating a BRFA subpage for " + formData["bot-name"] + " ([[User:APerson/easy-brfa|easy-brfa]])",
            text: brfaText
        } ).done ( function ( data ) {
            if ( data && data.edit && data.edit.result && data.edit.result == 'Success' ) {
                showStatus( "BRFA subpage created at <a href='" + mw.util.getUrl( pageTitle ) + "'>" + pageTitle + "</a>!" );
                deferred.resolve();
            } else {
                showStatus( "While creating BRFA subpage, the edit query returned an error. =(" );
                deferred.reject();
            }
        } ).fail ( function() {
            showStatus( "While creating BRFA subpage, the AJAX request failed." );
            deferred.reject();
        } );
        return deferred;
    }

    /*
     * Transcludes the BRFA.
     */
    transcludeBrfa = function ( botName, taskNumber ) {
        var deferred = $.Deferred();

        // Make a status element just for this edit
        var statusElement = showStatus( "Transcluding at WP:BRFA..." );
        // First, get the current wikitext for WP:BRFA
        var wikitext;
        $.getJSON(
            mw.util.wikiScript('api'),
            {
                format: 'json',
                action: 'query',
                prop: 'revisions',
                rvprop: 'content',
                rvlimit: 1,
                titles: "Wikipedia:Bots/Requests for approval"
            }
        ).done( function ( data ) {
            try {
                var pageId = Object.keys(data.query.pages)[0];
                wikitext = data.query.pages[pageId].revisions[0]['*'];

                statusElement.html( "Got WP:BRFA wikitext, processing..." );

                // Actually edit the content to include the new listing
                var taskNumberString = (taskNumber == 1) ? "" : (taskNumber + "");
                var newBrfaContent = wikitext.replace('directly below this message. -->', 'directly below this message. -->\n\{\{BRFA|' + botName + "|" + taskNumberString + '|Open\}\}');

                // Then, replace WP:BRFA with the new content
                $.ajax( {
                    url: mw.util.wikiScript( 'api' ),
                    type: 'POST',
                    dataType: 'json',
                    data: {
                        format: 'json',
                        action: 'edit',
                        title: "Wikipedia:Bots/Requests for approval",
                        summary: "Transcluding the BRFA for " + botName + " ([[User:APerson/easy-brfa|easy-brfa]])",
                        token: mw.user.tokens.get( 'csrfToken' ),
                        text: newBrfaContent
                    }
                } ).done ( function ( data ) {
                    if ( data && data.edit && data.edit.result && data.edit.result == 'Success' ) {
                        statusElement.html( "Transcluded page on <a href=" + mw.util.getUrl( "WP:BRFA" ) + ">WP:BRFA</a>!" );
                        deferred.resolve();
                    } else {
                        statusElement.html( "While transcluding on BRFA, the edit query returned an error. =(" );
                        deferred.reject();
                    }
                } ).fail ( function() {
                    statusElement.html( "While transcluding on BRFA, the ajax request failed." );
                    deferred.reject();
                } );
            } catch ( e ) {
                statusElement.html( "While transcluding on BRFA, there was an error." );
                console.log( "BRFA content request error: " + e.message );
                console.log( "BRFA content request response: " + JSON.stringify( data ) );
                deferred.reject();
            }
        } ).fail( function () {
            statusElement.html( "While getting the BRFA content, there was an AJAX error." );
            deferred.reject();
        } );
        return deferred;
    };

    // From http://stackoverflow.com/a/10834843/1757964
    function isNormalInteger( str ) {
        var n = ~~Number( str );
        return String( n ) === str && n >= 0;
    }
}( jQuery, mediaWiki ) );
//</nowiki>