/* Add any or all of these lines after the importScript line to set various options (the default values are shown):
var openUnread_maxnum = "10"; // Preset value for max number of pages
var openUnread_oldest = false; // Preset state of checkbox "oldest first". Set to true for checked, or false for unchecked
var openUnread_showAbove = false; // If set to true the "Open unread pages" button appears above the above the "Watchlist options" box, instead of below it
*/
mw.loader.using( ['mediawiki.util', 'mediawiki.api'], function () {
$(document).ready( function () {
if( mw.config.get('wgCanonicalSpecialPageName') != 'Watchlist' ) {
// only operate in Special: namespace, on Special:Watchlist
return;
}
// Set default options for any that haven't been set
if ( window.openUnread_maxnum === undefined ) { window.openUnread_maxnum = "10"; }
if ( window.openUnread_oldest === undefined ) { window.openUnread_oldest = true; }
if ( window.openUnread_showAbove === undefined ) { window.openUnread_showAbove = false; }
//Add a form to open multiple unread pages
var openUnread_form = '<div id="openUnread-input">'+
'<button id="openUnread-go">Open unread pages</button> '+
'(Options: <input type="text" name="openUnread-number" id="openUnread-number" style="width:2em;" value=' + openUnread_maxnum + ' /> pages max / '+
'<span class="mw-input-with-label"><input name="openUnread-order" id="openUnread-order" type="checkbox"> <label for="openUnread-order">oldest first</label></span>'+
')</div>';
if (openUnread_showAbove) {
$("form#mw-watchlist-form").before(openUnread_form);
$("#openUnread-input").css("margin-top","5px");
$("fieldset#mw-watchlist-options").css("margin-top", "0");
} else {
$("form#mw-watchlist-form").after(openUnread_form + '<hr>');
$("#openUnread-input").css("margin","5px 0");
$("fieldset#mw-watchlist-options").css("margin-bottom", "0");
}
if (openUnread_oldest) {
$("#openUnread-order").prop( "checked", "true" );
}
//Seen is reused for each button click to account for itmes which have already been opened
var seen = {};
var count = 0; // var increment on each button click iteration
// Start processing on button click
$("#openUnread-go").click(function() {
// get max number from input
var maxnum = parseInt( $('#openUnread-number').val() );
if (isNaN(maxnum) || maxnum < 1) {
msg = "\Error: \"" + $('#openUnread-number').val() + "\" is zero, negative, or not a number";
mw.notify( msg, { autoHide: false, tag: "WatchlistOpenUnread", title: "Watchlist-openUnread says:" } );
return; // error - zero, negative, or not a number
}
count++;
// get unread title links as array
var unread = $("li.mw-changeslist-line-watched, table.mw-changeslist-line-watched")
.find("a.mw-changeslist-title")
.map(function() {
return $(this).text();
})
.get();
// reverse order if oldest first option selected
if ( $('#openUnread-order').prop('checked') ) {
unread.reverse();
}
//remove duplicates
var unique_unread = [];
var len = unread.length;
var j = 0;
for (var i = 0; i < len; i++) {
var item = unread[i];
if( !(seen[item] >= count) ) { // because (undefined < number) is false
seen[item] = count;
unique_unread[j++] = item;
}
}
// reduce to the max number to open
if (unique_unread.length > maxnum) {
unique_unread = unique_unread.slice(0, maxnum);
}
// Mark each unique unread item as already seen for the next iterations
for (var u = 0; u < len; u++) {
seen[unique_unread[u]] = seen[unique_unread[u]]+1000;
}
// Callback for api errors
apiFailedCallback = function(code, result) {
var msg = "";
if ( code === "http" ) {
msg = "HTTP error: " + result.textStatus; // api_result contains the jqXHR object
} else if ( code === "ok-but-empty" ) {
msg = "Error: Got an empty response from the server</i></span>";
} else {
msg = "API error: " + code;
}
mw.notify( msg, { autoHide: false, tag: "WatchlistOpenUnread", title: "Watchlist-openUnread says:" } );
};
// Callback for getRevId: get old revision id for diff link
apiCallback_getRevId = function(result) {
var page_id = result.query.pageids[0];
var diff_oldid = result.query.pages[page_id].revisions && result.query.pages[page_id].revisions[1] && result.query.pages[page_id].revisions[1].revid;
var diff_title = mw.util.wikiUrlencode(result.query.pages[page_id].title);
if (!diff_oldid) {
window.open("https:" + mw.config.get('wgServer') + mw.config.get('wgScriptPath') +
"/index.php?title=" + diff_title, "_blank");
console.log("Could not find old revision for page "+ result.query.pages[page_id].title);
return;
}
window.open("https:" + mw.config.get('wgServer') + mw.config.get('wgScriptPath') +
"/index.php?title=" + diff_title +"&diff=cur&oldid=" + diff_oldid, "_blank");
};
// Function to get revision id of a page as of a particular timestamp
getRevId = function(pageid, timestamp) {
new mw.Api().get( {
action: 'query',
pageids: pageid,
prop: 'revisions',
rvprop: 'ids',
rvstart: timestamp,
rvlimit: '2',
indexpageids: 1,
rawcontinue: ''
} ).done( apiCallback_getRevId )
.fail( apiFailedCallback );
};
// Callback for getTimestamps: get timestamps/pageids to pass through to getRevId function
apiCallback_getTimestamps = function(result) {
var page_ids = result.query.pageids;
for (var k=0; k<page_ids.length; k++) {
var nts = result.query.pages[ page_ids[k] ].notificationtimestamp;
getRevId(page_ids[k], nts);
}
};
// Function to get timestamps from the api
getTimestamps = function(pagetitles) {
new mw.Api().get( {
action: 'query',
titles: pagetitles,
prop: 'info',
inprop: 'notificationtimestamp',
indexpageids: 1,
rawcontinue: ''
} ).done( apiCallback_getTimestamps )
.fail( apiFailedCallback );
};
// Split into lists of 50 (max number for api)
for (var ii=0; ii<unique_unread.length; ii+=50) {
getTimestamps(unique_unread.slice(ii, ii+49).join("|"));
}
// show pages as read on watchlist
$("li.mw-changeslist-line-watched, table.mw-changeslist-line-watched")
.find("a.mw-changeslist-title")
.filter(":contains('" + unique_unread.join("'), :contains('") + "')")
.closest(".mw-changeslist-line-watched")
.removeClass("mw-changeslist-line-watched")
.addClass("mw-changeslist-line-not-watched");
});
});
});