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 ) {

    mw.loader.load( "jquery.chosen" );

    mw.loader.load( "mediawiki.ui.input", "text/css" );



    var afdcCategories = { "m": "Media and music", "o": "Organization, corporation, or product", "b": "Biographical", "s": "Society topics", "w": "Web or Internet", "g": "Games or sports", "t": "Science and technology", "f": "Fiction and the arts", "p": "Places and transportation", "i": "Indiscernible or unclassifiable topic", "u": "Not sorted yet" };

    var ADVERTISEMENT = " ([[User:Enterprisey/delsort|assisted]])";



    var currentAfdcCat = "";

    var currentDelsortCategories = [];



    if ( mw.config.get( "wgPageName" ).indexOf("Wikipedia:Articles_for_deletion/") != -1 &&

         mw.config.get( "wgPageName" ).indexOf("Wikipedia:Articles_for_deletion/Log/") == -1) {

        var portletLink = mw.util.addPortletLink("p-cactions", "#", "Delsort", "pt-delsort", "Perform deletion sorting");



        // Load list of delsort categories

        var delsortCategoriesPromise = $.ajax( {

            url: "https://en.wikipedia.org/?action=raw&title=" + encodeURIComponent( "Wikipedia:WikiProject Deletion sorting/Computer-readable.json" ) + "&maxage=86400&smaxage=86400",

            dataType: "json"

        } )



        $( portletLink ).click( function ( e ) {

            e.preventDefault();



            // Validation for new custom fields

            var validateCustomCat = function ( container ) {

                var categoryName = container.children( "input" ).first().val();

                $.getJSON(

                    mw.util.wikiScript("api"),

                    {

                        format: "json",

                        action: "query",

                        prop: "pageprops",

                        titles: "Wikipedia:WikiProject Deletion sorting/" + categoryName

                    }

                ).done( function ( data ) {

                    var setStatus = function ( status ) {

                        var text = "Not sure";

                        var imageSrc = "https://upload.wikimedia.org/wikipedia/commons/a/ad/Question_mark_grey.png";

                        switch( status ) {

                        case "d":

                            text = "Doesn't exist";

                            imageSrc = "https://upload.wikimedia.org/wikipedia/commons/5/5f/Red_X.svg";

                            break;

                        case "e":

                            text = "Exists";

                            imageSrc = "https://upload.wikimedia.org/wikipedia/commons/1/16/Allowed.svg";

                            break;

                        }

                        container.children( ".category-status" ).empty()

                            .append( $( "<img>", { "src": imageSrc,

                                "style": "padding: 0 5px; width: 20px; height: 20px" } ) )

                            .append( text );

                    };

                    if( data && data.query && data.query.pages ) {

                        if( data.query.pages.hasOwnProperty( "-1" ) ) {

                            setStatus( "d" );

                        } else {

                            setStatus( "e" );

                        }

                    } else {

                        setStatus( "n" );

                    }

                } );

            };



            // Define a function to add a new custom field, used below

            var addCustomField = function ( e ) {

                $( "<div>" )

                    .appendTo( "#delsort-td" )

                    .css( "width", "100%" )

                    .css( "margin", "0.25em auto" )

                    .append( $( "<input>" )

                             .attr( "type", "text" )

                             .addClass( "mw-ui-input mw-ui-input-inline custom-delsort-field" )

                             .change( function ( e ) {

                                 validateCustomCat( $( this ).parent() );

                             } ) )

                    .append( $( "<span>" ).addClass( "category-status" ) )

                    .append( " (" )

                    .append( $( "<img>", { "src": "https://upload.wikimedia.org/wikipedia/commons/a/a2/Crystal_128_reload.svg",

                        "style": "width: 15px; height: 15px; cursor: pointer" } )

                             .click( function ( e ) {

                                 validateCustomCat( $( this ).parent() );

                             } ) )

                    .append( ")" )

                    .append( $( "<button>" )

                             .addClass( "mw-ui-button mw-ui-destructive mw-ui-quiet" )

                             .text( "Remove" )

                             .click( function () {

                                 $( this ).parent().remove();

                             } ) );

            };



            $( "#mw-content-text" ).prepend(

'<div style="border: thin solid rgb(197, 197, 197); box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.25); border-radius: 3px; padding: 5px; position: relative;" id="delsort">' +

'  <div id="delsort-title" style="font-size: larger; font-weight: bold; text-align: center;">Select a deletion sorting category</div>' +

'  <table style="margin: 2em auto; border-collapse: collapse;" id="delsort-table">' +

'    <tr style="font-size: larger"><th>AFDC</th><th>DELSORT</th></tr>' +

'    <tr>' +

'      <td style="padding-right: 10px;">' +

'        <table id="afdc">' +

'        </table>' +

'      </td>' +

'      <td style="border-left: solid black thick; padding-left: 10px; vertical-align: top;" id="delsort-td">' +

'          <select multiple="multiple" data-placeholder="Select a deletion sorting category..."></select>' +

'          <button id="add-custom-button" class="mw-ui-button mw-ui-progressive mw-ui-quiet">Add custom</button>' +

'      </td>' +

'    </tr>' +

'  </table>' +

'  <button style="position: absolute; top: 5px; right: 5px;" id="close-button" class="mw-ui-button mw-ui-destructive mw-ui-quiet">Close</button>' +

'</div>' );

            $( "#add-custom-button" ).click( addCustomField );

            $( "#close-button" ).click( function () { $( "#delsort" ).remove(); } );



            var afdcHtml = "";

            Object.keys( afdcCategories ).forEach( function ( code, i ) {

                if ( i % 2 === 0 ) afdcHtml += "<tr>";

                afdcHtml += "<td><input type='radio' name='afdc' value='" + code + "' id='afdc-" + code + "' /><label for='afdc-" + code + "'>" + afdcCategories code  + "</label></td>";

                if ( i % 2 !== 0 ) afdcHtml += "</tr>";

            } );



            // If there are an odd number of AFDC cats, we need to close off the last row

            if ( Object.keys( afdcCategories ).length % 2 !== 0 ) afdcHtml += "</tr>";



            $( "#afdc" ).html( afdcHtml );



            // Build the deletion sorting categories

            delsortCategoriesPromise.done( function ( delsortCategories ) {

                $.each( delsortCategories, function ( groupName, categories ) {

                    var group = $( "<optgroup>" )

                        .appendTo( "#delsort select" )

                        .attr( "label", groupName );

                    $.each( categories, function ( index, category ) {

                        group.append( $( "<option>" )

                                      .val( category )

                                      .text( category )

                                      .addClass( "delsort-category" ) );

                    } );

                } );



                getWikitext( mw.config.get( "wgPageName" ) ).then( function ( wikitext ) {

                    autofillAfdc( wikitext );



                    // Autofill the delsort box

                    var DELSORT_RE = /:<small class="delsort-notice">(.+?)<\/small>/g;

                    var DELSORT_LIST_RE = /\[\[Wikipedia:WikiProject Deletion sorting\/(.+?)\|.+?\]\]/;

                    var delsortMatch;

                    var delsortListMatch;

                    do {

                        delsortMatch = DELSORT_RE.exec( wikitext );

                        if( delsortMatch !== null ) {

                            delsortListMatch = DELSORT_LIST_RE.exec( delsortMatch1 );

                            if( delsortListMatch !== null ) {

                                currentDelsortCategories.push( delsortListMatch1 );

                                var delsortOption = document.querySelector( "option.delsort-category[value='" + delsortListMatch1 + "']" );

                                if( delsortOption ) {

                                    delsortOption.selected = true;

                                }

                            }

                        }

                    } while( delsortMatch );



                    // Now that we've updated the underlying <select>, ask Chosen to

                    // update the visible search box

                    $( "#delsort select" ).trigger( "chosen:updated" );

                } ); // end getWikitext

            } ); // end delsortCategoriesPromise



            // Initialize the special chosen.js select box

            // (some code stolen from http://stackoverflow.com/a/27445788)

            $( "#delsort select" ).chosen();

            $( "#delsort .chzn-container" ).css( "text-align", "left" );



            // Add the button that triggers sorting

            $( "#delsort" ).append( $( "<div>" )

                    .css( "text-align", "center" )

                    .append( $( "<button> ")

                        .addClass( "mw-ui-button" )

                        .addClass( "mw-ui-progressive" )

                        .attr( "id", "sort-button" )

                        .text( "Save changes" )

                        .click( function () {



                            // Make a status list

                            $( "#delsort" ).append( $( "<ul> ")

                                                    .attr( "id", "status" ) );



                            // Build a list of categories

                            var categories = $( "#delsort select" ).val() || [];

                            $( ".custom-delsort-field" ).each( function ( index, element ) {

                                categories.push( $( element ).val() );

                            } );

                            categories = categories.filter( Boolean ); // remove empty strings

                            categories = removeDups( categories );



                            // Only allow categories that aren't already there

                            categories = categories.filter( function ( elem ) {

                                return currentDelsortCategories.indexOf( elem ) < 0;

                            } );

                            

                            // Obtain the target AFDC category, brought to you by http://stackoverflow.com/a/24886483/1757964

                            var afdcTarget = document.querySelector("input[name='afdc']:checked").value;

                            

                            // Actually do the delsort

                            saveChanges( categories, afdcTarget );

                        } ) ) );

        } );

    } // End if ( mw.config.get( "wgPageName" ).indexOf('Wikipedia:Articles_for_deletion/') ... )



    /*

     * Autofills the AFDC radio button group based on the current

     * page's wikitext

     */

    function autofillAfdc( wikitext ) {

        var regexMatch = /REMOVE THIS TEMPLATE WHEN CLOSING THIS AfD(?:\|(.*))?}}/.exec( wikitext );

        if ( regexMatch ) {

            var templateParameter = regexMatch1];

            if ( templateParameter ) {

                currentAfdcCat = templateParameter;

                if ( templateParameter.length === 1 ) {

                    var currentClass = templateParameter.toLowerCase();

                    $( "#afdc-" + currentClass ).prop( "checked", true );

                }

            }

        }

    }



    /*

     * Saves the changes to the current discussion page by adding delsort notices (if applicable) and updating the AFDC cat

     */

    function saveChanges( cats, afdcTarget ) {

        var changingAfdcCat = currentAfdcCat.toLowerCase() !== afdcTarget;



        // Indicate to the user that we're doing some deletion sorting

        $( "#delsort-table" ).remove();

        $( "#delsort #sort-button" )

            .text( "Sorting " + ( changingAfdcCat ? "and categorizing " : "" ) + "discussion..." )

            .prop( "disabled", true )

            .fadeOut( 400, function () {

                $( this ).remove();

            } );

        var categoryTitleComponent = ( cats.length === 1 ) ? ( "the \"" + cats0 + "\" category" ) : ( cats.length + " categories" );

        var afdcTitleComponent = changingAfdcCat ? " and categorizing it as " + afdcCategories afdcTarget  : "";

        $( "#delsort-title" )

            .html( "Sorting discussion into " + categoryTitleComponent + afdcTitleComponent + "<span id=\"delsort-dots\"></span>" );



        // Start the animation, using super-advanced techniques

        var animationInterval = setInterval( function () {

            $( "#delsort-dots" ).text( $( "#delsort-dots" ).text() + "." );

            if( $( "#delsort-dots" ).text().length > 3 ) {

                $( "#delsort-dots" ).text( "" );

            }

        }, 600 );



        // Place (a) notification(s) on the discussion and update its AFDC cat

        var editDiscussionDeferred = postDelsortNoticesAndUpdateAfdc( cats, afdcTarget );



        // List the discussion at the DELSORT pages

        var deferreds = cats.map( listAtDelsort );



        // We still have to wait for the discussion to be edited

        deferreds.push( editDiscussionDeferred );



        // When everything's done, say something

        $.when.apply( $, deferreds ).then( function () {



            // Call the done hook

            if( window.delsortDoneHook ) {

                window.delsortDoneHook();

            }



            // We're done!

            $( "#delsort-title" )

                .text( "Done " + ( changingAfdcCat ? "updating the discussion's AFDC category and " : "" ) + "sorting discussion into " + categoryTitleComponent + "." );

            showStatus( "<b>Done!</b> " + ( changingAfdcCat ? "The discussion's AFDC was updated and it was" : "Discussion was" ) + " sorted into " + categoryTitleComponent + ". (" )

                .append( $( "<a>" )

                         .text( "reload" )

                         .attr( "href", "#" )

                         .click( function () { document.location.reload( true ); } ) )

                .append( ")" );

            clearInterval( animationInterval );

        } );

    }



    /*

     * Adds a new status to the status list, and returns the newly-displayed element.

     */

    function showStatus( newStatus ) {

        return $( "<li>" )

             .appendTo( "#delsort ul#status" )

             .html( newStatus );

    }



    /*

     * Adds some notices to the discussion page that this discussion was sorted.

     */

    function postDelsortNoticesAndUpdateAfdc( cats, afdcTarget ) {

        var changingAfdcCat = currentAfdcCat.toLowerCase() !== afdcTarget,

            deferred = $.Deferred(),

            statusElement = showStatus( "Updating the discussion page..." );



        getWikitext( mw.config.get( "wgPageName" ) ).then( function ( wikitext ) {

            try {

                statusElement.html( "Processing wikitext..." );



                // Process wikitext



                // First, add delsort notices

                wikitext += createDelsortNotices( cats );



                // Then, update the AFDC category

                var afdcMatch = wikitext.match( /REMOVE THIS TEMPLATE WHEN CLOSING THIS AfD/ );

                if ( afdcMatch && afdcMatch 0  ) {

                    var afdcMatchIndex = wikitext.indexOf( afdcMatch 0  ) + afdcMatch 0 ].length,

                        charAfterTemplateName = wikitext afdcMatchIndex ];

                    if ( charAfterTemplateName === "}" ) {

                        wikitext = wikitext.slice( 0, afdcMatchIndex ) + "|" + afdcTarget.toUpperCase() + wikitext.slice( afdcMatchIndex );

                    } else if ( charAfterTemplateName === "|" ) {

                        wikitext = wikitext.replace( "|" + currentAfdcCat + "}}", "|" + afdcTarget.toUpperCase() + "}}" );

                    }

                }



                statusElement.html( "Processed wikitext. Saving..." );



                var catPlural = ( cats.length === 1 ) ? "" : "s";

                $.ajax( {

                    url: mw.util.wikiScript( "api" ),

                    type: "POST",

                    dataType: "json",

                    data: {

                        format: "json",

                        action: "edit",

                        title: mw.config.get( "wgPageName" ),

                        summary: "Updating nomination page with notices" + ( changingAfdcCat ? " and new AFDC cat" : "" ) + ADVERTISEMENT,

                        token: mw.user.tokens.get( "csrfToken" ),

                        text: wikitext

                    }

                } ).done ( function ( data ) {

                    if ( data && data. && data..result && data..result == "Success" ) {

                        statusElement.html( cats.length + " notice" + catPlural + " placed on the discussion!" );

                        if ( changingAfdcCat ) {

                            if ( currentAfdcCat ) {

                                var formattedCurrentAfdcCat = currentAfdcCat.length === 1 ? afdcCategories currentAfdcCat.toLowerCase()  : currentAfdcCat;

                                showStatus( "Discussion's AFDC category was changed from " + formattedCurrentAfdcCat + " to " + afdcCategories afdcTarget  + "." );

                            } else {

                                showStatus( "Discussion categorized under " + afdcCategories afdcTarget  + " with AFDC." );

                            }

                        }

                        deferred.resolve();

                    } else {

                        statusElement.html( "While editing the current discussion page, the edit query returned an error. =(" );

                        deferred.reject();

                    }

                } ).fail ( function() {

                    statusElement.html( "While editing the current discussion page, the AJAX request failed." );

                    deferred.reject();

                } );

            } catch ( e ) {

                statusElement.html( "While getting the current page content, there was an error." );

                console.log( "Current page content request error: " + e.message );

                deferred.reject();

            }

        } ).fail( function () {

            statusElement.html( "While getting the current content, there was an AJAX error." );

            deferred.reject();

        } );

        return deferred;

    }



    /*

     * Turns a list of delsort categories into a number of delsort template notice substitutions.

     */

    function createDelsortNotices( cats ) {

        if ( Array.isArray(cats) && ! cats.length ) return '';

        var appendText = "\n{{subst:Deletion sorting/multi";

        cats.forEach( function ( cat ) {

            appendText += "|" + cat;

        } );

        return appendText + "|sig=~~" + "~~}}"; // string concat to prevent it from being transformed into my signature

    }

    

    /*

     * Adds a listing at the DELSORT page for the category.

     */

    function listAtDelsort( cat ) {



        // Make a status element just for this category

        var statusElement = showStatus( "Listing this discussion at DELSORT/" +

                                        cat + "..." );



        // Clarify our watchlist behavior for this edit

        var allowedWatchlistBehaviors = "watch", "unwatch", "preferences",

                "nochange"];

        var watchlistBehavior = "nochange"; // no watchlist change by default

        if( window.delsortWatchlist && allowedWatchlistBehaviors.indexOf(

                window.delsortWatchlist.toLowerCase() ) >= 0 ) {

            watchlistBehavior = window.delsortWatchlist.toLowerCase();

        }



        var listTitle = "Wikipedia:WikiProject Deletion sorting/" + cat;

        

        // First, get the current wikitext for the DELSORT page

        return $.getJSON(

            mw.util.wikiScript("api"),

            {

                format: "json",

                action: "query",

                prop: "revisions",

                rvprop: "content",

                rvslots: "main",

                rvlimit: 1,

                titles: listTitle,

                redirects: "true",

                formatversion: 2,

            }

        ).then( function ( data ) {

            var wikitext = data.query.pages0].revisions0].slots.main.content;

            var properTitle = data.query.pages0].title;

            try {

                statusElement.html( "Got the DELSORT/" + cat + " listing wikitext, processing..." );

                

                // Actually edit the content to include the new listing

                var newDelsortContent = wikitext.replace("directly below this line -->", "directly below this line -->\n\{\{" + mw.config.get("wgPageName") + "\}\}");

                

                // Then, replace the DELSORT listing with the new content

                $.ajax( {

                    url: mw.util.wikiScript( "api" ),

                    type: "POST",

                    dataType: "json",

                    data: {

                        format: "json",

                        action: "edit",

                        title: properTitle,

                        summary: "Listing [[" + mw.config.get("wgPageName") + "]]" + ADVERTISEMENT,

                        token: mw.user.tokens.get( "csrfToken" ),

                        text: newDelsortContent,

                        watchlist: watchlistBehavior

                    }

                } ).done ( function ( data ) {

                    if ( data && data. && data..result && data..result == "Success" ) {

                        statusElement.html( "Listed page at <a href=" + mw.util.getUrl( listTitle ) + ">the " + cat + " deletion sorting list</a>!" );

                    } else {

                        statusElement.html( "While listing at DELSORT/" + cat + ", the edit query returned an error. =(" );

                    }

                } ).fail ( function() {

                    statusElement.html( "While listing at DELSORT/" + cat + ", the ajax request failed." );

                } );

            } catch ( e ) {

                statusElement.html( "While getting the DELSORT/" + cat + " content, there was an error." );

                console.log( "DELSORT content request error: " + e.message );

                //console.log( "DELSORT content request response: " + JSON.stringify( data ) );

            }

        } ).fail( function () {

            statusElement.html( "While getting the DELSORT/" + cat + " content, there was an AJAX error." );

        } );

    }



    /**

     * Gets the wikitext of a page with the given title (namespace required).

     */

    function getWikitext( title ) {

        return $.getJSON(

            mw.util.wikiScript("api"),

            {

                format: "json",

                action: "query",

                prop: "revisions",

                rvprop: "content",

                rvslots: "main",

                rvlimit: 1,

                titles: title,

                formatversion: 2,

            }

        ).then( function ( data ) {

            return data.query.pages0].revisions0].slots.main.content;

        } );

    }



    /**

     * Removes duplicates from an array.

     */

    function removeDups( arr ) {

        var obj = {};

        for( var i = 0; i < arr.length; i++ ) {

            objarri]] = 0;

        }

        return Object.keys( obj );

    }

}( jQuery, mediaWiki ) );

//</nowiki>
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 ) {

    mw.loader.load( "jquery.chosen" );

    mw.loader.load( "mediawiki.ui.input", "text/css" );



    var afdcCategories = { "m": "Media and music", "o": "Organization, corporation, or product", "b": "Biographical", "s": "Society topics", "w": "Web or Internet", "g": "Games or sports", "t": "Science and technology", "f": "Fiction and the arts", "p": "Places and transportation", "i": "Indiscernible or unclassifiable topic", "u": "Not sorted yet" };

    var ADVERTISEMENT = " ([[User:Enterprisey/delsort|assisted]])";



    var currentAfdcCat = "";

    var currentDelsortCategories = [];



    if ( mw.config.get( "wgPageName" ).indexOf("Wikipedia:Articles_for_deletion/") != -1 &&

         mw.config.get( "wgPageName" ).indexOf("Wikipedia:Articles_for_deletion/Log/") == -1) {

        var portletLink = mw.util.addPortletLink("p-cactions", "#", "Delsort", "pt-delsort", "Perform deletion sorting");



        // Load list of delsort categories

        var delsortCategoriesPromise = $.ajax( {

            url: "https://en.wikipedia.org/?action=raw&title=" + encodeURIComponent( "Wikipedia:WikiProject Deletion sorting/Computer-readable.json" ) + "&maxage=86400&smaxage=86400",

            dataType: "json"

        } )



        $( portletLink ).click( function ( e ) {

            e.preventDefault();



            // Validation for new custom fields

            var validateCustomCat = function ( container ) {

                var categoryName = container.children( "input" ).first().val();

                $.getJSON(

                    mw.util.wikiScript("api"),

                    {

                        format: "json",

                        action: "query",

                        prop: "pageprops",

                        titles: "Wikipedia:WikiProject Deletion sorting/" + categoryName

                    }

                ).done( function ( data ) {

                    var setStatus = function ( status ) {

                        var text = "Not sure";

                        var imageSrc = "https://upload.wikimedia.org/wikipedia/commons/a/ad/Question_mark_grey.png";

                        switch( status ) {

                        case "d":

                            text = "Doesn't exist";

                            imageSrc = "https://upload.wikimedia.org/wikipedia/commons/5/5f/Red_X.svg";

                            break;

                        case "e":

                            text = "Exists";

                            imageSrc = "https://upload.wikimedia.org/wikipedia/commons/1/16/Allowed.svg";

                            break;

                        }

                        container.children( ".category-status" ).empty()

                            .append( $( "<img>", { "src": imageSrc,

                                "style": "padding: 0 5px; width: 20px; height: 20px" } ) )

                            .append( text );

                    };

                    if( data && data.query && data.query.pages ) {

                        if( data.query.pages.hasOwnProperty( "-1" ) ) {

                            setStatus( "d" );

                        } else {

                            setStatus( "e" );

                        }

                    } else {

                        setStatus( "n" );

                    }

                } );

            };



            // Define a function to add a new custom field, used below

            var addCustomField = function ( e ) {

                $( "<div>" )

                    .appendTo( "#delsort-td" )

                    .css( "width", "100%" )

                    .css( "margin", "0.25em auto" )

                    .append( $( "<input>" )

                             .attr( "type", "text" )

                             .addClass( "mw-ui-input mw-ui-input-inline custom-delsort-field" )

                             .change( function ( e ) {

                                 validateCustomCat( $( this ).parent() );

                             } ) )

                    .append( $( "<span>" ).addClass( "category-status" ) )

                    .append( " (" )

                    .append( $( "<img>", { "src": "https://upload.wikimedia.org/wikipedia/commons/a/a2/Crystal_128_reload.svg",

                        "style": "width: 15px; height: 15px; cursor: pointer" } )

                             .click( function ( e ) {

                                 validateCustomCat( $( this ).parent() );

                             } ) )

                    .append( ")" )

                    .append( $( "<button>" )

                             .addClass( "mw-ui-button mw-ui-destructive mw-ui-quiet" )

                             .text( "Remove" )

                             .click( function () {

                                 $( this ).parent().remove();

                             } ) );

            };



            $( "#mw-content-text" ).prepend(

'<div style="border: thin solid rgb(197, 197, 197); box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.25); border-radius: 3px; padding: 5px; position: relative;" id="delsort">' +

'  <div id="delsort-title" style="font-size: larger; font-weight: bold; text-align: center;">Select a deletion sorting category</div>' +

'  <table style="margin: 2em auto; border-collapse: collapse;" id="delsort-table">' +

'    <tr style="font-size: larger"><th>AFDC</th><th>DELSORT</th></tr>' +

'    <tr>' +

'      <td style="padding-right: 10px;">' +

'        <table id="afdc">' +

'        </table>' +

'      </td>' +

'      <td style="border-left: solid black thick; padding-left: 10px; vertical-align: top;" id="delsort-td">' +

'          <select multiple="multiple" data-placeholder="Select a deletion sorting category..."></select>' +

'          <button id="add-custom-button" class="mw-ui-button mw-ui-progressive mw-ui-quiet">Add custom</button>' +

'      </td>' +

'    </tr>' +

'  </table>' +

'  <button style="position: absolute; top: 5px; right: 5px;" id="close-button" class="mw-ui-button mw-ui-destructive mw-ui-quiet">Close</button>' +

'</div>' );

            $( "#add-custom-button" ).click( addCustomField );

            $( "#close-button" ).click( function () { $( "#delsort" ).remove(); } );



            var afdcHtml = "";

            Object.keys( afdcCategories ).forEach( function ( code, i ) {

                if ( i % 2 === 0 ) afdcHtml += "<tr>";

                afdcHtml += "<td><input type='radio' name='afdc' value='" + code + "' id='afdc-" + code + "' /><label for='afdc-" + code + "'>" + afdcCategories code  + "</label></td>";

                if ( i % 2 !== 0 ) afdcHtml += "</tr>";

            } );



            // If there are an odd number of AFDC cats, we need to close off the last row

            if ( Object.keys( afdcCategories ).length % 2 !== 0 ) afdcHtml += "</tr>";



            $( "#afdc" ).html( afdcHtml );



            // Build the deletion sorting categories

            delsortCategoriesPromise.done( function ( delsortCategories ) {

                $.each( delsortCategories, function ( groupName, categories ) {

                    var group = $( "<optgroup>" )

                        .appendTo( "#delsort select" )

                        .attr( "label", groupName );

                    $.each( categories, function ( index, category ) {

                        group.append( $( "<option>" )

                                      .val( category )

                                      .text( category )

                                      .addClass( "delsort-category" ) );

                    } );

                } );



                getWikitext( mw.config.get( "wgPageName" ) ).then( function ( wikitext ) {

                    autofillAfdc( wikitext );



                    // Autofill the delsort box

                    var DELSORT_RE = /:<small class="delsort-notice">(.+?)<\/small>/g;

                    var DELSORT_LIST_RE = /\[\[Wikipedia:WikiProject Deletion sorting\/(.+?)\|.+?\]\]/;

                    var delsortMatch;

                    var delsortListMatch;

                    do {

                        delsortMatch = DELSORT_RE.exec( wikitext );

                        if( delsortMatch !== null ) {

                            delsortListMatch = DELSORT_LIST_RE.exec( delsortMatch1 );

                            if( delsortListMatch !== null ) {

                                currentDelsortCategories.push( delsortListMatch1 );

                                var delsortOption = document.querySelector( "option.delsort-category[value='" + delsortListMatch1 + "']" );

                                if( delsortOption ) {

                                    delsortOption.selected = true;

                                }

                            }

                        }

                    } while( delsortMatch );



                    // Now that we've updated the underlying <select>, ask Chosen to

                    // update the visible search box

                    $( "#delsort select" ).trigger( "chosen:updated" );

                } ); // end getWikitext

            } ); // end delsortCategoriesPromise



            // Initialize the special chosen.js select box

            // (some code stolen from http://stackoverflow.com/a/27445788)

            $( "#delsort select" ).chosen();

            $( "#delsort .chzn-container" ).css( "text-align", "left" );



            // Add the button that triggers sorting

            $( "#delsort" ).append( $( "<div>" )

                    .css( "text-align", "center" )

                    .append( $( "<button> ")

                        .addClass( "mw-ui-button" )

                        .addClass( "mw-ui-progressive" )

                        .attr( "id", "sort-button" )

                        .text( "Save changes" )

                        .click( function () {



                            // Make a status list

                            $( "#delsort" ).append( $( "<ul> ")

                                                    .attr( "id", "status" ) );



                            // Build a list of categories

                            var categories = $( "#delsort select" ).val() || [];

                            $( ".custom-delsort-field" ).each( function ( index, element ) {

                                categories.push( $( element ).val() );

                            } );

                            categories = categories.filter( Boolean ); // remove empty strings

                            categories = removeDups( categories );



                            // Only allow categories that aren't already there

                            categories = categories.filter( function ( elem ) {

                                return currentDelsortCategories.indexOf( elem ) < 0;

                            } );

                            

                            // Obtain the target AFDC category, brought to you by http://stackoverflow.com/a/24886483/1757964

                            var afdcTarget = document.querySelector("input[name='afdc']:checked").value;

                            

                            // Actually do the delsort

                            saveChanges( categories, afdcTarget );

                        } ) ) );

        } );

    } // End if ( mw.config.get( "wgPageName" ).indexOf('Wikipedia:Articles_for_deletion/') ... )



    /*

     * Autofills the AFDC radio button group based on the current

     * page's wikitext

     */

    function autofillAfdc( wikitext ) {

        var regexMatch = /REMOVE THIS TEMPLATE WHEN CLOSING THIS AfD(?:\|(.*))?}}/.exec( wikitext );

        if ( regexMatch ) {

            var templateParameter = regexMatch1];

            if ( templateParameter ) {

                currentAfdcCat = templateParameter;

                if ( templateParameter.length === 1 ) {

                    var currentClass = templateParameter.toLowerCase();

                    $( "#afdc-" + currentClass ).prop( "checked", true );

                }

            }

        }

    }



    /*

     * Saves the changes to the current discussion page by adding delsort notices (if applicable) and updating the AFDC cat

     */

    function saveChanges( cats, afdcTarget ) {

        var changingAfdcCat = currentAfdcCat.toLowerCase() !== afdcTarget;



        // Indicate to the user that we're doing some deletion sorting

        $( "#delsort-table" ).remove();

        $( "#delsort #sort-button" )

            .text( "Sorting " + ( changingAfdcCat ? "and categorizing " : "" ) + "discussion..." )

            .prop( "disabled", true )

            .fadeOut( 400, function () {

                $( this ).remove();

            } );

        var categoryTitleComponent = ( cats.length === 1 ) ? ( "the \"" + cats0 + "\" category" ) : ( cats.length + " categories" );

        var afdcTitleComponent = changingAfdcCat ? " and categorizing it as " + afdcCategories afdcTarget  : "";

        $( "#delsort-title" )

            .html( "Sorting discussion into " + categoryTitleComponent + afdcTitleComponent + "<span id=\"delsort-dots\"></span>" );



        // Start the animation, using super-advanced techniques

        var animationInterval = setInterval( function () {

            $( "#delsort-dots" ).text( $( "#delsort-dots" ).text() + "." );

            if( $( "#delsort-dots" ).text().length > 3 ) {

                $( "#delsort-dots" ).text( "" );

            }

        }, 600 );



        // Place (a) notification(s) on the discussion and update its AFDC cat

        var editDiscussionDeferred = postDelsortNoticesAndUpdateAfdc( cats, afdcTarget );



        // List the discussion at the DELSORT pages

        var deferreds = cats.map( listAtDelsort );



        // We still have to wait for the discussion to be edited

        deferreds.push( editDiscussionDeferred );



        // When everything's done, say something

        $.when.apply( $, deferreds ).then( function () {



            // Call the done hook

            if( window.delsortDoneHook ) {

                window.delsortDoneHook();

            }



            // We're done!

            $( "#delsort-title" )

                .text( "Done " + ( changingAfdcCat ? "updating the discussion's AFDC category and " : "" ) + "sorting discussion into " + categoryTitleComponent + "." );

            showStatus( "<b>Done!</b> " + ( changingAfdcCat ? "The discussion's AFDC was updated and it was" : "Discussion was" ) + " sorted into " + categoryTitleComponent + ". (" )

                .append( $( "<a>" )

                         .text( "reload" )

                         .attr( "href", "#" )

                         .click( function () { document.location.reload( true ); } ) )

                .append( ")" );

            clearInterval( animationInterval );

        } );

    }



    /*

     * Adds a new status to the status list, and returns the newly-displayed element.

     */

    function showStatus( newStatus ) {

        return $( "<li>" )

             .appendTo( "#delsort ul#status" )

             .html( newStatus );

    }



    /*

     * Adds some notices to the discussion page that this discussion was sorted.

     */

    function postDelsortNoticesAndUpdateAfdc( cats, afdcTarget ) {

        var changingAfdcCat = currentAfdcCat.toLowerCase() !== afdcTarget,

            deferred = $.Deferred(),

            statusElement = showStatus( "Updating the discussion page..." );



        getWikitext( mw.config.get( "wgPageName" ) ).then( function ( wikitext ) {

            try {

                statusElement.html( "Processing wikitext..." );



                // Process wikitext



                // First, add delsort notices

                wikitext += createDelsortNotices( cats );



                // Then, update the AFDC category

                var afdcMatch = wikitext.match( /REMOVE THIS TEMPLATE WHEN CLOSING THIS AfD/ );

                if ( afdcMatch && afdcMatch 0  ) {

                    var afdcMatchIndex = wikitext.indexOf( afdcMatch 0  ) + afdcMatch 0 ].length,

                        charAfterTemplateName = wikitext afdcMatchIndex ];

                    if ( charAfterTemplateName === "}" ) {

                        wikitext = wikitext.slice( 0, afdcMatchIndex ) + "|" + afdcTarget.toUpperCase() + wikitext.slice( afdcMatchIndex );

                    } else if ( charAfterTemplateName === "|" ) {

                        wikitext = wikitext.replace( "|" + currentAfdcCat + "}}", "|" + afdcTarget.toUpperCase() + "}}" );

                    }

                }



                statusElement.html( "Processed wikitext. Saving..." );



                var catPlural = ( cats.length === 1 ) ? "" : "s";

                $.ajax( {

                    url: mw.util.wikiScript( "api" ),

                    type: "POST",

                    dataType: "json",

                    data: {

                        format: "json",

                        action: "edit",

                        title: mw.config.get( "wgPageName" ),

                        summary: "Updating nomination page with notices" + ( changingAfdcCat ? " and new AFDC cat" : "" ) + ADVERTISEMENT,

                        token: mw.user.tokens.get( "csrfToken" ),

                        text: wikitext

                    }

                } ).done ( function ( data ) {

                    if ( data && data. && data..result && data..result == "Success" ) {

                        statusElement.html( cats.length + " notice" + catPlural + " placed on the discussion!" );

                        if ( changingAfdcCat ) {

                            if ( currentAfdcCat ) {

                                var formattedCurrentAfdcCat = currentAfdcCat.length === 1 ? afdcCategories currentAfdcCat.toLowerCase()  : currentAfdcCat;

                                showStatus( "Discussion's AFDC category was changed from " + formattedCurrentAfdcCat + " to " + afdcCategories afdcTarget  + "." );

                            } else {

                                showStatus( "Discussion categorized under " + afdcCategories afdcTarget  + " with AFDC." );

                            }

                        }

                        deferred.resolve();

                    } else {

                        statusElement.html( "While editing the current discussion page, the edit query returned an error. =(" );

                        deferred.reject();

                    }

                } ).fail ( function() {

                    statusElement.html( "While editing the current discussion page, the AJAX request failed." );

                    deferred.reject();

                } );

            } catch ( e ) {

                statusElement.html( "While getting the current page content, there was an error." );

                console.log( "Current page content request error: " + e.message );

                deferred.reject();

            }

        } ).fail( function () {

            statusElement.html( "While getting the current content, there was an AJAX error." );

            deferred.reject();

        } );

        return deferred;

    }



    /*

     * Turns a list of delsort categories into a number of delsort template notice substitutions.

     */

    function createDelsortNotices( cats ) {

        if ( Array.isArray(cats) && ! cats.length ) return '';

        var appendText = "\n{{subst:Deletion sorting/multi";

        cats.forEach( function ( cat ) {

            appendText += "|" + cat;

        } );

        return appendText + "|sig=~~" + "~~}}"; // string concat to prevent it from being transformed into my signature

    }

    

    /*

     * Adds a listing at the DELSORT page for the category.

     */

    function listAtDelsort( cat ) {



        // Make a status element just for this category

        var statusElement = showStatus( "Listing this discussion at DELSORT/" +

                                        cat + "..." );



        // Clarify our watchlist behavior for this edit

        var allowedWatchlistBehaviors = "watch", "unwatch", "preferences",

                "nochange"];

        var watchlistBehavior = "nochange"; // no watchlist change by default

        if( window.delsortWatchlist && allowedWatchlistBehaviors.indexOf(

                window.delsortWatchlist.toLowerCase() ) >= 0 ) {

            watchlistBehavior = window.delsortWatchlist.toLowerCase();

        }



        var listTitle = "Wikipedia:WikiProject Deletion sorting/" + cat;

        

        // First, get the current wikitext for the DELSORT page

        return $.getJSON(

            mw.util.wikiScript("api"),

            {

                format: "json",

                action: "query",

                prop: "revisions",

                rvprop: "content",

                rvslots: "main",

                rvlimit: 1,

                titles: listTitle,

                redirects: "true",

                formatversion: 2,

            }

        ).then( function ( data ) {

            var wikitext = data.query.pages0].revisions0].slots.main.content;

            var properTitle = data.query.pages0].title;

            try {

                statusElement.html( "Got the DELSORT/" + cat + " listing wikitext, processing..." );

                

                // Actually edit the content to include the new listing

                var newDelsortContent = wikitext.replace("directly below this line -->", "directly below this line -->\n\{\{" + mw.config.get("wgPageName") + "\}\}");

                

                // Then, replace the DELSORT listing with the new content

                $.ajax( {

                    url: mw.util.wikiScript( "api" ),

                    type: "POST",

                    dataType: "json",

                    data: {

                        format: "json",

                        action: "edit",

                        title: properTitle,

                        summary: "Listing [[" + mw.config.get("wgPageName") + "]]" + ADVERTISEMENT,

                        token: mw.user.tokens.get( "csrfToken" ),

                        text: newDelsortContent,

                        watchlist: watchlistBehavior

                    }

                } ).done ( function ( data ) {

                    if ( data && data. && data..result && data..result == "Success" ) {

                        statusElement.html( "Listed page at <a href=" + mw.util.getUrl( listTitle ) + ">the " + cat + " deletion sorting list</a>!" );

                    } else {

                        statusElement.html( "While listing at DELSORT/" + cat + ", the edit query returned an error. =(" );

                    }

                } ).fail ( function() {

                    statusElement.html( "While listing at DELSORT/" + cat + ", the ajax request failed." );

                } );

            } catch ( e ) {

                statusElement.html( "While getting the DELSORT/" + cat + " content, there was an error." );

                console.log( "DELSORT content request error: " + e.message );

                //console.log( "DELSORT content request response: " + JSON.stringify( data ) );

            }

        } ).fail( function () {

            statusElement.html( "While getting the DELSORT/" + cat + " content, there was an AJAX error." );

        } );

    }



    /**

     * Gets the wikitext of a page with the given title (namespace required).

     */

    function getWikitext( title ) {

        return $.getJSON(

            mw.util.wikiScript("api"),

            {

                format: "json",

                action: "query",

                prop: "revisions",

                rvprop: "content",

                rvslots: "main",

                rvlimit: 1,

                titles: title,

                formatversion: 2,

            }

        ).then( function ( data ) {

            return data.query.pages0].revisions0].slots.main.content;

        } );

    }



    /**

     * Removes duplicates from an array.

     */

    function removeDups( arr ) {

        var obj = {};

        for( var i = 0; i < arr.length; i++ ) {

            objarri]] = 0;

        }

        return Object.keys( obj );

    }

}( jQuery, mediaWiki ) );

//</nowiki>

Videos

Youtube | Vimeo | Bing

Websites

Google | Yahoo | Bing

Encyclopedia

Google | Yahoo | Bing

Facebook