Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
/*
This script make easy the review process on [[Commons:Quality_images_candidates]]
It prevent edit conflicts and you can vote with a simple click (selecting the vote type in the combobox below of each image)
Please, feel free of contact to me to improve this tool. Thanks
*/
mw.loader.using("mediawiki.api.edit").done(function() {
    "use strict";

    mw.util.addCSS(
        "	#voting_bar {			" +
        "	    position: fixed;	" +
        "	    bottom: 0;			" +
        "	    width: 100%;		" +
        "		height: 40px;		" +
        "		padding: 15px;		" +
        "		border: 1px solid #a2a9b1; " +
        "		background-color: #E6E6FA; " +
        "	}   					"+
        "	#loading_ {			" +
        "      display: inline-block !important;	" +
    	"      padding-left: 10px;	" +
    	"      color: green;	" +
    	"      font-weight: bold;	" +
    	"	}   					" +
    	"	#confirm_ {			" +
        "      display: inline-block !important;	" +
    	"      padding-left: 10px;	" +
    	"      color: red;	" +
        "	}   					"
    );
    
    const CONFIRM_BAR = "<div id='voting_bar'><span id='confirm_review' style='margin:auto !important' class='submit ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary ui-button-large' role='button'><span class='ui-button-icon-primary ui-icon-green ui-icon ui-icon-check'>&nbsp;</span><span class='ui-button-text'>Confirm reviews</span></span><div id='loading_'></div><div id='confirm_'></div><p style='padding-left: 50px;padding-right:50px;float:right;'><input type='checkbox' id='hidereviews' value='first_checkbox'> <label for='hidereviews'> Hide reviewed nominations</label></p></div>";
    const QIC_PAGE_DESTINY = "Commons:Quality_images_candidates/candidate_list";
    const NOMINATION_CONTAINER = "div.qi-nomination";
    const REVIEW_MESSAGE = "Dear wikiuser, please enter your review comment";
    const USERNAME = mw.config.get("wgUserName");
    let TITLE = mw.config.get("wgPageName");
    if (TITLE == "Commons:Quality_images_candidates") TITLE = QIC_PAGE_DESTINY;
    let api = new mw.Api();
    let opt = {
        "Nomination": {
            color: "#0000FF",
            message: ""
        },
        "Promotion": {
            color: "lime",
            message: "Good quality."
        },
        "Decline": {
            color: "red",
            message: "Insufficient quality."
        },
        "Comment": {
            color: "#0000FF",
            message: ""
        },
        "Discuss": {
            color: "#EEEE00",
            message: "I disagree."
        }
    };
    const comboValues = {
        "Promotion": "Promotion",
        "Decline": "Decline",
        "Nomination": "Comment",
        "Discuss": "Discuss",
        "": "..."
    };
    let votes = [];
    let reviewCount = 0;

	function _loading(show) {
			if (show) {
				 $('#confirm_').text('');
				 $('#loading_').text('Sending reviews..');
			}
		    else {
		    	$('#loading_').text('');
		    }
	}
	function _confirmMessage () {
		if (reviewCount > 0) {
			$('#confirm_').text(reviewCount + ' pending review confirmations'); 
		}
	}
    function getSection(section) {
		_loading(true);
        return api.get({
                action: "query",
                prop: "revisions",
                rvprop: ["content", "timestamp"],
                titles: [TITLE],
                section: section, // Future support of section edition
                formatversion: "2",
                curtimestamp: true
            })
            .then(function(data) {
                var page, revision;
                page = data.query.pages[0];
                revision = page.revisions[0];
                return revision.content;
            });
    }

    function editSection(section, content) {
        $.ajax({
            url: mw.util.wikiScript("api"),
            data: {
                format: "json",
                action: "edit",
                title: TITLE,
                summary: "adding vote using [[User:The Photographer/QICvote.js]]",
                text: content,
                //section: section, // Future support of section edition
                token: mw.user.tokens.get("editToken")
            },
            dataType: 'json',
            type: 'POST',
            success: function(data) {
                if (data && data.edit && data.edit.result == "Success") {
                    _loading(false);
                    votes = [];
                    reviewCount = 0;
                    $('#confirm_').text('');
                } else if (data && data.error) {
                    throw new Error('Error: API returned error code "' + data.error.code + '": ' + data.error.info);
                } else {
                    throw new Error('Error: Unknown result from API.');
                }
            },
            error: function(xhr) {
                alert('Error: Request failed.');
            }
        });
    }

    function getSectionId(element) {
        var url = $(element).parent().parent().parent().find("h2 span a").last().attr("href");
        var results = new RegExp('[\?&]section=([^&#]*)').exec(url);
        return results[1] || 0;
    }

    function createCombo() {
        var $cmb = $("<select style='width:100%; margin:0px !important;' class='submit ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary ui-button-blue ui-button-large' />");

        $.each(comboValues, function(key, value) {
            $cmb
                .append($("<option>", {
                        value: key
                    })
                    .text(value));
        });

        $cmb.val("");

        return $cmb;
    }

    function _getImageName(aElement) {
        let imageName = null;

        const imageNode = $(aElement).parent().find("a.image").last().attr("href").split(":");

        if (imageNode.length > 0) {
            if (imageNode[1].indexOf(".") !== -1) {
                imageName = imageNode[1];
            }
        }

        return imageName;
    }

    function _remplaceLast(str, word, newWord) {
        var n = str.lastIndexOf(word);
        str = str.slice(0, n) + str.slice(n).replace(word, newWord);
        return str;
    }

    function escapeRegExp(str) {
        return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    function _getSignature() {
        return ' [[User:' + USERNAME + '|' + USERNAME + ']] ' + new Date().toUTCString();
    }

    function _addVote(content, image, type, comment) {
        const reg = escapeRegExp(image) + "(.*)\\n";
        let nomination = content.match(new RegExp(reg, "g"))[0];
        let newNomination = nomination.replace(/\{\{\/(Nomination|Promotion|Decline|Discuss)\|/g, '{{/' + type + '|');

        const eol = (newNomination.indexOf("|}}") !== -1) ? "<br />" : "|";
        newNomination = _remplaceLast(newNomination, "}}", eol + comment + _getSignature() + "}}");

        return content.replace(nomination, newNomination);
    }

    function scapeFilenames(filesname) {
        function removeSpaces(match) {
            return match.replace(/\ /g, '_');
        }
        return filesname.replace(/File:(.*?)\|\{\{+/g, removeSpaces);
    }

    function _addVotes() {
        $.each(votes, function(section, votesSection) {
            if ((typeof votesSection !== 'undefined') && (votesSection.length > 0)) {
                getSection(section - 1).then(function(content) {
                    content = scapeFilenames(content);
                    $.each(votesSection, function(i, vote) {
                        content = _addVote(content, vote.image, vote.type, vote.comment);
                    });
                    editSection(section, content);
                });
            }
        });
    }

    function _getNominationContainer(e) {
        return $(e).parent().find(NOMINATION_CONTAINER);
    }

    function _nullVote(cmb) {
        let nullVote = false;
        if ($(cmb).val() === "") {
            _getNominationContainer(cmb).find("ul li i").text("Review needed");
            _getNominationContainer(cmb).css("border-color", "#0000FF");
            $(cmb).val("");
            nullVote = true;
        }
        return nullVote;
    }

    function _getSelection(cmb) {
        return opt[$(cmb).val()];
    }

    function _removePreviusVote(cmb) {
        _getNominationContainer(cmb).find("ul li > .coment").remove();
    }

    function _setBoderColorVote(cmb, colorBorder) {
        _getNominationContainer(cmb).css("border-color", colorBorder);
    }

    function _setVoteTitle(cmb) {
        _getNominationContainer(cmb).find("ul li i").append("b").text($(cmb).val());
    }

    function _getCommentElement(comment) {
        return $('<div />', {
            text: comment,
            "class": "coment"
        });
    }

    function _getSignatureElement() {
        return $('<a />', {
            href: String("/wiki/User:" + USERNAME),
            text: USERNAME,
            "class": "coment"
        });
    }

    function _getDateElement() {
        return $('<p />', {
            "class": "coment",
            text: String(new Date().toUTCString())
        });
    }
    
    function _hideReviewds(e) {
    	$(".gallerybox").each(function() {
          if($(this).find(NOMINATION_CONTAINER).find("ul").first().find("li").last().find("i").text() !== "Review needed" && $(e).is(':checked'))
          {
          	$(this).hide();
          }
           else
           {
           	$(this).show();
           }
        });
        
        $( ".gallery.mw-gallery-traditional" ).each(function( index ) {
		  if($(this).children(':visible').length === 0) {
		   $(this).hide();
		    $(this).prev().hide();
		  } else {
		   $(this).show();
		   $(this).prev().show();
		  }
		});
    }

    function _onChangeVote(cmb, section) {
        if (_nullVote(cmb)) return;

        let selection;
        let imageName;
        let comment = "";

        selection = _getSelection(cmb);

        _setVoteTitle(cmb);
        _setBoderColorVote(cmb, selection.color);
        _removePreviusVote(cmb);

        comment = prompt(REVIEW_MESSAGE, selection.message);
        let $comment = _getCommentElement(comment);

        let $signature = _getSignatureElement();
        let $date = _getDateElement();

        $(cmb).parent().find(NOMINATION_CONTAINER).
        find("ul li").last().append($comment).
        append($signature).
        append($date);

        imageName = _getImageName(cmb);

        if (typeof votes[section] === "undefined") {
            votes[section] = [];
        }
       
        votes[section].push({
            image: decodeURIComponent(imageName),
            comment: comment,
            type: $(cmb).val()
        });
        
        reviewCount++;
    }

    if (TITLE == QIC_PAGE_DESTINY) {
        let section;
        let $cmb;
        $("body").append(CONFIRM_BAR);
        $('#confirm_review').on('click', function() {
            _addVotes();
        });
        $(".gallerybox").each(function() {
            $cmb = createCombo();
            $(this).append($cmb);
            section = getSectionId(this);
            $cmb.on("change", function() {
                _onChangeVote(this, section);
                _confirmMessage ();
            });
        });
        
        $( "#hidereviews" ).change(function() {
		  _hideReviewds(this);
		});

    }
});