Pengguna:Hidayatsrf/customWatchlists.js

Catatan: Setelah menyimpan, Anda harus memintas tembolok (cache) peramban Anda untuk melihat perubahannya. Google Chrome, Firefox, Microsoft Edge dan Safari: Tahan tombol ⇧ Shift dan klik Muat ulang (Reload) di tombol bilah alat. Untuk detail dan instruksi tentang peramban lain, lihat halaman menghapus singgahan (Inggris).

//https://en.wiki-indonesia.club/wiki/User:MusikAnimal/customWatchlists.js
// customWatchlists.js
// version 0.1.2
(function() {
    $("head").append(importStylesheet("User:Hidayatsrf/customWatchlists.css"));
   
    var addCwLinkListener = function() {
        $(".cw-add").click(function() {
            if($("#cw-overlay")[0]) return false;
            var pageName = new mw.Title($(this).siblings(".mw-title").text());
            pageName = pageName.getNamespacePrefix()+pageName.getMain();
            getCustomWatchlists().then(setupCactionInterface.bind(this, pageName),setupCactionInterface.bind(this, null));
        });
    };
   
    var getCustomWatchlists = function() {
        return Promise.resolve($.get("/wiki/User:"+wgUserName+"/watchlists?action=raw"));
    };
   
    var formatDate = function(dateObj) {
        // TODO: replace monthNames with wgMonthNames
        var monthNames = [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ];
        return (dateObj.getHours()+100).toString().slice(-2)+":"+(dateObj.getMinutes()+100).toString().slice(-2)+", "+(dateObj.getUTCDate()+100).toString().slice(-2)+" "+monthNames[dateObj.getUTCMonth()]+" "+dateObj.getUTCFullYear();
    };
   
    var generateListItem = function(data) {
        var mwName = new mw.Title(data.title);
        var pageUrl = "/w/index.php?title="+mwName.getNamespacePrefix()+mwName.getMain().replace(/'/g, "%27"),
            editDate = new Date(data.timestamp);
        if(data.newlen) {
            var lengthDiff = data.newlen - data.oldlen;
            var diffClass = lengthDiff >= 0 ? "mw-plusminus-pos" : "mw-plusminus-neg";
        }
        return "<li class='mw-line-even mw-changeslist-line-not-watched'>" +
            "("+
                "<a href='"+pageUrl+"&diff=prev&oldid="+data.revid+"' class='nonimage'>diff</a>&nbsp;| " +
                "<a href='"+pageUrl+"&action=history' class='nonimage'>hist</a>&nbsp;| " +
                "<a href='javascript:' class='cw-add'>cw</a>" +
            ")&nbsp;" +
            "<span class='mw-changeslist-separator'>. .</span>&nbsp;" +
            "<span class='mw-changeslist-date'>"+formatDate(editDate)+"</span>&nbsp;" +
            "<span class='mw-title'><a href='/wiki/"+encodeURI(data.title).replace(/'/g, "%27")+"' class='mw-changeslist-title nonimage'>"+data.title+"</a></span>&nbsp;" +
            (data.newlen ? "<span class='mw-changeslist-separator'>. .</span>&nbsp;<span dir='ltr' class='"+diffClass+"'>("+(lengthDiff > 0 ? "+" : "")+lengthDiff+")</span> " : "") +
            "<span class='mw-changeslist-separator'>. .</span>&nbsp;" +
            "<a href='/wiki/User:"+data.user+"' class='mw-userlink nonimage'>"+data.user+"</a> " +
            "(<a href='/wiki/User talk:"+data.user+"'>talk</a> | <a href='/wiki/Special:Contributions/"+data.user+"'>contribs</a>)" +
            (data.parsedcomment ? "&nbsp;<span style='font-style:italic'>(" + data.parsedcomment + ")</span>" : "") +
        "</li>";
    };
   
    var showCustomWatchlist = function(type,lists,target,limit,allrev) {
        var apiRoot = "/w/api.php?action=query";
        var pages = JSON.parse(JSON.stringify(lists[target]));
        var pagesLength = pages.length;
        for(var i=0; i<pagesLength; i++) {
            var mwPageName = new mw.Title(pages[i]);
            if(mwPageName.namespace % 2 === 0) {
                pages.push(mwPageName.getNamespacePrefix().slice(0,-1) + (mwPageName.namespace === 0 ? "Talk:" : "_talk:") + mwPageName.getMain());
            }
        }
        $(".mw-changeslist").html("Loading...");
       
        var newHtml = "";
        if(type === "rc") {
            $.get(apiRoot+"&list=watchlist&wlprop=user|parsedcomment|timestamp|sizes|title|ids&wltype=edit&wllimit="+limit+(allrev === true ? "&wlallrev=true" : "")+"&format=json", function(data) {
                var matches = $.grep(data.query.watchlist, function(el){
                    var mwName = new mw.Title(el.title);
                    return pages.indexOf(mwName.getNamespacePrefix()+mwName.getMain()) >= 0;
                });
                for(var i=0; i<matches.length; i++) {
                    newHtml += generateListItem(matches[i]);
                }
                $(".mw-changeslist").html(newHtml);
                addCwLinkListener();
                mw.hook( 'wikipage.content' ).fire($('.mw-changeslist'));
            });
        } else {
            var queryablePages = $.map(pages,function(p,i){return encodeURIComponent(p).replace(/'/g, "%27")}).join("|");
            $.get(apiRoot+"&prop=revisions&rvprop=ids|timestamp|user|parsedcomment&titles="+queryablePages+"&format=json", function(data) {
                var sortedData = [];
                for(var pageId in data.query.pages) {
                    if(parseInt(pageId) > 0) {
                        var pageData = data.query.pages[pageId];
                        sortedData.push({
                            parsedcomment : pageData.revisions[0].parsedcomment,
                            revid: pageData.revisions[0].revid,
                            timestamp: pageData.revisions[0].timestamp,
                            title: pageData.title,
                            user: pageData.revisions[0].user
                        });
                    }
                }
                $.each(sortedData.sort(function(x,y) {
                    if($("#cw-rw-options input:checked").val() === "timestamp") {
                        return new Date(y.timestamp).getTime() - new Date(x.timestamp).getTime();
                    } else {
                        return x.title.localeCompare(y.title);
                    }
                }), function(i,v) {
                    newHtml += generateListItem(v);
                });
                $(".mw-changeslist").html(newHtml);
                addCwLinkListener();
                mw.hook( 'wikipage.content' ).fire($('.mw-changeslist'));
            });
        }
    };
   
    var showCustomWatchlistsForm = function(appendHtml) {
        var html = "<form id='custom_watchlist_form'><fieldset>" +
                "<legend>Custom watchlists (<a href='//en.wiki-indonesia.club/w/index.php?title=User:MusikAnimal/customWatchlists'>documentation</a>)</legend>" + appendHtml;
        $("#mw-watchlist-form").after(html);
    };
   
    var setupCactionInterface = function(data, argName) {
        if(argName) {
            pageName = data;
            data = argName;
        } else {
            pageName = wgPageName;
        }
        var customWatchlists = data ? JSON.parse(data.split("\n")[0]) : {};
        var customWatchlistNames = Object.keys(customWatchlists),
            inWatchlists = [];
       
        for(var wl in customWatchlists) {
           
            if(customWatchlists[wl].indexOf(pageName.replace("_talk:",":").replace("Talk:","")) !== -1) {
                inWatchlists.push(wl);
            }
        }
       
        var html = "<div id='cw-overlay'>" +
            "<div class='header'>" +
                "Add/remove page to custom watchlists" +
                "<span class='closer-x' onclick=\"$('#cw-overlay').remove();\"></span>" +
            "</div>" +
            "<div id='cw-overlay-body'>" +
                (argName ? "<p style='margin-top:0'>Page name: <i>"+pageName.replace(/_/g, " ")+"</i></p>" : "");
       
        for(var i=0; i < customWatchlistNames.length; i++) {
            var listName = customWatchlistNames[i];
            html += "<span><input class='cw-option' type='checkbox' value='"+i+"' "+(inWatchlists.indexOf(listName) !== -1 ? "checked data-index='"+customWatchlists[listName].indexOf(pageName)+"'" : "")+" id='cw-option-"+i+"' /><label for='cw-option-"+i+"'>"+listName+"</label> (<a class='cw-delete' href='javascript:' data-id='"+i+"'>del</a>)</span>";
        }
       
        html += "<div id='cw-overlay-new-watchlist'>" +
                "<input class='cw-option' type='checkbox' value='-1' id='cw-new-option' "+(data ? "" : "checked")+" /><label for='cw-new-option'>New watchlist</label>" +
                "<input type='text' id='cw-overlay-new-watchlist-input' placeholder='Enter watchlist name' "+(data ? "" : "style='display:inline-block'")+" />" +
            "</div><button id='cw-overlay-selector-submit'>Save changes</button></div></div>";
       
        $("body").append(html);
       
        if(!data) $("#cw-overlay-new-watchlist-input").focus();
       
        $("#cw-new-option").change(function() {
            if($(this).is(":checked")) {
                $("#cw-overlay-new-watchlist-input").show().focus();
            } else {
                $("#cw-overlay-new-watchlist-input").hide();
            }
        });
       
        $(".cw-delete").click(function() {
            if($(this).text() === "undel") {
                $("#cw-option-"+$(this).data('id')).prop('checked',false).siblings("label").removeClass("disabled");
                $("#cw-option-"+$(this).data('id')).data('delete',null);
                $(this).text("del");
            } else {
                var name = customWatchlistNames[$(this).data('id')];
                var cwToDelete = customWatchlists[name];
                if(confirm("Mark the watchlist \""+name+"\" and all it's "+cwToDelete.length+" entries for deletion?")) {
                    $(this).text("undel");
                    $("#cw-option-"+$(this).data('id')).data('delete',true);
                    $("#cw-option-"+$(this).data('id')).prop('checked',true).one("click", function() {
                        $(this).siblings("a").trigger("click");
                    }).siblings("label").addClass("disabled");
                }
            }
        });
       
        $("#cw-overlay-selector-submit").click({
            customWatchlistNames: customWatchlistNames,
            customWatchlists: customWatchlists,
            inWatchlists: inWatchlists,
            pageName : pageName
        }, function(e) {
            $("#cw-overlay-selector-submit").replaceWith("Saving...");
            var cw = e.data.customWatchlists,
                iw = e.data.inWatchlists,
                pageName = e.data.pageName.replace("_talk:",":").replace("Talk:",":"),
                toWatch = false,
                updateStr = "";

            $.each($(".cw-option"), function(i) {
                var id = parseInt($(this).val());
                var key = id < 0 ? $("#cw-overlay-new-watchlist-input").val().replace(/[^\w\s]/gi, '') : customWatchlistNames[id];
                var exists = iw.indexOf(key) >= 0;
               
                if($(this).is(":checked")) {
                    if($(this).data("delete")) {
                        updateStr = "Deleted the custom watchlist <b>"+key+"</b>.";
                        delete cw[key];
                    } else {
                        toWatch = true;
                        if(id < 0) {
                            updateStr = "Created the custom watchlist <b>"+key+"</b> with <b>"+pageName+"</b>";
                            cw[key] = [pageName];
                        } else {
                            updateStr = "Added <b>"+pageName+"</b> to the custom watchlist <b>"+key+"</b>";
                            cw[key].push(pageName);
                        }
                    }
                } else if(exists) {
                    updateStr = "Removed <b>"+pageName+"</b> from the custom watchlist <b>"+key+"</b>";
                    cw[key].splice($(this).data('index'),1);
                }
            });
           
            var stringifiedCw = JSON.stringify(cw)+"\nBacklink: [[User:MusikAnimal/customWatchlists]]";

            var api = new mw.Api();
            api.watch(pageName).done(function(watchResult) {
                api.postWithToken( "edit", {
                    action: "edit",
                    title: "User:"+wgUserName+"/watchlists",
                    summary: "updating [[User:MusikAnimal/customWatchlists|custom watchlists]]",
                    text: stringifiedCw
                }).done(function(result, jqXHR) {
                    $("#cw-overlay-body").html("Success!");
                    mw.notify($("<div>"+updateStr+"</div"));
                    setTimeout(function() {
                        $("#cw-overlay").remove();
                    },3000);
                }).fail(function(code, result) {
                    if ( code === "http" ) {
                        mw.log( "HTTP error: " + result.textStatus ); // result.xhr contains the jqXHR object
                    } else if ( code === "ok-but-empty" ) {
                        mw.log( "Got an empty response from the server" );
                    } else {
                        mw.log( "API error: " + code );
                    }
                });
            }).fail(function(code, result) {
                if ( code === "http" ) {
                    mw.log( "HTTP error: " + result.textStatus ); // result.xhr contains the jqXHR object
                } else if ( code === "ok-but-empty" ) {
                    mw.log( "Got an empty response from the server" );
                } else {
                    mw.log( "API error: " + code );
                }
            });
        });
    };
   
    if(wgRelevantPageName === "Special:Watchlist") {
        getCustomWatchlists().then(function(data) {
            var customWatchlists = JSON.parse(data.split("\n")[0]);
            var customWatchlistNames = Object.keys(customWatchlists);
            var html = "<p><label for='custom_watchlist_selector'>Custom list:</label>&nbsp;<select id='custom_watchlist_selector'>";

            for(var i=0; i < customWatchlistNames.length; i++) {
                var listName = customWatchlistNames[i];
                html += "<option value='"+i+"'>"+listName+"</option>";
            }
           
            html += "</select></p>"+
                "<p id='cw-list-type'>Show:&nbsp;<label><input type='radio' name='cw-display-type' value='rc' checked /> Recent changes</label>&nbsp;<label><input type='radio' name='cw-display-type' value='rw' /> Raw watchlist</label></p>" +
                "<p id='cw-rw-options' style='display:none'>Sorting:&nbsp;<label><input type='radio' name='cw-rw-sorting' value='timestamp' checked /> Last edited</label>&nbsp;<label><input type='radio' name='cw-rw-sorting' value='title' />Alphabetical</label></p>" +
                "<p id='cw-rc-options'><label for='custom_watchlist_limit'>Search limit (from base watchlist):</label>&nbsp;<select id='custom_watchlist_limit'>";
            var limitArr = [50,100,250,500,1000,2500,5000];
            for(var j=0; j<limitArr.length; j++) {   
                html += "<option val='"+limitArr[j]+"'>"+limitArr[j]+"</option>";
            }

            html += "</select><br/>" +
                "<input type='checkbox' id='custom_watchlist_all_rev' value='wlallrev' /><label for='custom_watchlist_all_rev'>Include multiple revisions to same page</label></p>" +
                "<p><button id='custom_watchlist_submit'>Go</button></fieldset></p></form>";

            showCustomWatchlistsForm(html);
           
            $("#custom_watchlist_submit").click(function(e) {
                e.preventDefault();
                showCustomWatchlist($("#cw-list-type input[type=radio]:checked").val(),customWatchlists,customWatchlistNames[parseInt($("#custom_watchlist_selector").val())],$("#custom_watchlist_limit").val(),$("#custom_watchlist_all_rev").is(":checked"));
            });
            $("#custom_watchlist_form input[type=radio]").click(function() {
                if($(this).val() === "rc") {
                    $("#cw-rc-options").show();
                    $("#cw-rw-options").hide();
                } else {
                    $("#cw-rc-options").hide();
                    $("#cw-rw-options").show();
                }
            });
        }, function() {
            showCustomWatchlistsForm("<p>No <a href='https://en.wiki-indonesia.club/wiki/User:MusikAnimal/customWatchlists'>custom watchlists</a> yet! Go to a <a href='/wiki/Special:Random'>page</a> and create a custom watchlist by selecting the \"Custom Watchlists&hellip;\" item from the More menu.</p>");
        });
        $(".mw-changeslist .special li").each(function() {
            $anchor = $(this).find("a").eq(1);
            if($anchor.text() === "hist" && !$anchor.siblings(".wikibase-edit").length) {
                $anchor.after("&nbsp;| <a class='cw-add' href='javascript:'>cw</a>");
            }
        });
        addCwLinkListener();
    } else if(wgNamespaceNumber >= 0) {
        mw.util.addPortletLink(
            'p-cactions',
            'javascript:',
            'Custom watchlist…',
            'ca-add-to-cw'
        );
        $("#ca-add-to-cw").click(function() {
            if($("#cw-overlay")[0]) return false;
            getCustomWatchlists().then(setupCactionInterface,setupCactionInterface.bind(this, null, null));
        });
    }
}());