User:DreamRimmer/massMessageLite.js
Appearance
Code that you insert on this page could contain malicious content capable of compromising your account. If you import a script from another page with "importScript", "mw.loader.load", "iusc", or "lusc", take note that this causes you to dynamically load a remote script, which could be changed by others. Editors are responsible for all edits and actions they perform, including by scripts. User scripts are not centrally supported and may malfunction or become inoperable due to software changes. A guide to help you find broken scripts is available. If you are unsure whether code you are adding to this page is safe, you can ask at the appropriate village pump. This code will be executed when previewing this page. |
![]() | This user script seems to have a documentation page at User:DreamRimmer/massMessageLite. |
//WARNING: You take full responsibility for any actions taken using this script.
//You must read and understand all relevant Wikipedia policies and abide by them
//when using this tool; failure to do so may result in being blocked from editing.
//<nowiki>
$(document).ready(function() {
var isPaused = false, pauseResumeButton, minorEditCheckbox, createIfMissingCheckbox, talkMessageCheckInterval, lastTalkRevId = null, operatorPausedByNewMessage = false;
function initializeMassMessage() {
$('#mw-content-text > p').remove();
$('#firstHeading').text('massMessageLite');
$('#mw-content-text').empty()
.append(
$('<p>').html('<span style="font-weight: bold; color: red;">Warning:</span> <span style="font-weight: bold; color: black;">You take full responsibility for any actions taken using this script. You must read and understand all relevant <a href="/wiki/Wikipedia:Policies_and_guidelines" target="_blank">Wikipedia policies</a> and abide by them when using this tool; failure to do so may result in being <a href="/wiki/Wikipedia:Blocking_policy" target="_blank">blocked from editing</a>.</span>'),
$('<div>').css({'margin-bottom': '20px', 'font-size': '1.1em'}).html(
'Use the form below to send messages to a specified list. All fields are required. See <a href="/wiki/User:DreamRimmer/massMessageLite" target="_blank">User:DreamRimmer/massMessageLite</a> for more details.'
)
);
var frameContainer = $('<div>')
.addClass('mw-htmlform-ooui-wrapper oo-ui-layout oo-ui-panelLayout oo-ui-panelLayout-padded oo-ui-panelLayout-framed')
.css({'max-width': '950px', 'margin': '0 auto 2em auto', 'padding': '1em 1.5em'});
var deliveredPages = [], skippedPages = [], deliveredDiffs = {}, linksContainer, deliveredBox, skippedBox;
var pagesTextarea = new OO.ui.MultilineTextInputWidget({
placeholder: 'User talk:Example user\nUser talk:Example user2\nWikipedia talk:Example',
autosize: true,
rows: 10
}),
subjectInputField = new OO.ui.TextInputWidget({
placeholder: 'Subject of the message'
}),
messageTextarea = new OO.ui.MultilineTextInputWidget({
placeholder: 'Body of the message',
autosize: true,
rows: 10
}),
summaryInputField = new OO.ui.TextInputWidget({
placeholder: 'Edit summary'
}),
visualPreviewButton = new OO.ui.ButtonWidget({
label: 'Preview',
flags: ['primary']
}),
startButton = new OO.ui.ButtonWidget({
label: 'Send Message',
icon: 'alert',
flags: ['primary', 'progressive'],
disabled: true
}),
cancelButton = new OO.ui.ButtonWidget({
label: 'Cancel',
flags: ['primary', 'destructive'],
href: 'https:' + mw.config.get('wgServer')
}),
skipDuplicateCheckbox = new OO.ui.CheckboxInputWidget({
selected: false
}),
minorEditCheckbox = new OO.ui.CheckboxInputWidget({
selected: false
}),
createIfMissingCheckbox = new OO.ui.CheckboxInputWidget({
selected: false
}),
followRedirectsCheckbox = new OO.ui.CheckboxInputWidget({
selected: true, // checked by default
disabled: typeof window.massMessageLiteEnableRedirectCheckbox === "undefined" ? true : !window.massMessageLiteEnableRedirectCheckbox
}),
pauseResumeButton = new OO.ui.ButtonWidget({
label: 'Pause',
icon: new OO.ui.IconWidget({icon: 'pause', flags: ['progressive']}),
flags: ['progressive'],
disabled: true
}),
logContainer = $("<ul>").css({
'padding': '10px',
'margin-top': '10px',
'border': 'none',
'display': 'table-row',
'width': 'auto',
'font-size': 'small',
'transition': 'background 0.2s',
'overflow-y': 'auto',
'max-height': '260px',
'min-height': '80px'
}).addClass('mml-log-container').hide(),
previewContainer = $('<div>').css({
'padding': '10px',
'margin': '10px',
'overflow': 'auto',
'min-height': '200px',
'max-height': '400px',
'border': '1px solid #ccc',
'width': '65%',
'display': 'table-row'
}).hide();
pagesTextarea.$element.attr('title', 'Enter one page per line (e.g., User talk:Example user).');
subjectInputField.$element.attr('title', 'Required. Subject line for the message section.');
messageTextarea.$element.attr('title', 'Required. The body of the message to send.');
summaryInputField.$element.attr('title', 'Required. Edit summary for the message delivery.');
skipDuplicateCheckbox.$element.attr('title', 'If checked, skips pages where a section with the same subject already exists.');
minorEditCheckbox.$element.attr('title', 'If checked, marks all deliveries as minor edits.');
createIfMissingCheckbox.$element.attr('title', 'If checked, creates the page if it does not exist.');
var followRedirectsTooltip = followRedirectsCheckbox.isDisabled()
? "The script will leave messages on target page if a redirect page. Please check documentation to know how to enable this button."
: "If checked, the script will leave messages on the redirect target (default). Uncheck to leave messages on the redirect page itself.";
followRedirectsCheckbox.$element.attr('title', followRedirectsTooltip);
visualPreviewButton.$element.attr('title', 'Preview how your message will look.');
startButton.$element.attr('title', 'Send the message to all listed pages.');
cancelButton.$element.attr('title', 'Cancel and leave this tool.');
pauseResumeButton.$element.attr('title', 'Pause or resume delivery process.');
$('<style>').prop('type', 'text/css').html(`
.mml-log-entry {
border-radius: 8px;
margin-bottom: 5px;
padding: 5px 7px 5px 3px;
transition: background 0.18s, box-shadow 0.18s;
background: #fff;
opacity: 0;
animation: mml-fadein 0.45s forwards;
}
.mml-log-entry:hover {
background: #e7f1ff;
box-shadow: 0 1px 7px rgba(120,160,255,0.07);
}
@keyframes mml-fadein {
from { opacity: 0; transform: translateY(10px);}
to { opacity: 1; transform: none;}
}
.mml-log-link {
color: #2a4dad !important;
text-decoration: none;
font-weight: 600;
cursor: pointer;
}
.mml-diff-link {
color: #0b8200 !important;
margin-left: 0.8em;
font-size: 90%;
vertical-align: middle;
text-decoration: underline;
font-weight: 500;
}
.mml-log-container {
scrollbar-width: thin;
scrollbar-color: #b8c6e5 #f8fafc;
}
.mml-log-container::-webkit-scrollbar {
width: 8px;
background: #f8fafc;
opacity: 0;
transition: opacity 0.3s;
}
.mml-log-container:hover::-webkit-scrollbar {
opacity: 1;
}
.mml-log-container::-webkit-scrollbar-thumb {
background: #b8c6e5;
border-radius: 6px;
}
`).appendTo(document.head);
linksContainer = $('<div>').css({'margin':'10px 0 0 0','padding':'5px 0 0 0','display':'none'});
deliveredBox = $('<div>').css({'display':'none','margin':'6px 0'}).append(
$('<textarea readonly style="width:700px;min-height:120px;max-height:400px;resize:vertical;font-family:monospace;font-size:13px;box-sizing:border-box;" title="Pages where the message was delivered."></textarea>')
);
skippedBox = $('<div>').css({'display':'none','margin':'6px 0'}).append(
$('<textarea readonly style="width:700px;min-height:120px;max-height:400px;resize:vertical;font-family:monospace;font-size:13px;box-sizing:border-box;" title="Pages where the message could not be delivered."></textarea>')
);
linksContainer.append(
$('<a href="#" style="margin-right:15px;font-weight:bold;" id="show-delivered-list" title="Show the list of pages where the message was delivered.">Show delivered pages</a>'),
$('<a href="#" style="font-weight:bold;" id="show-skipped-list" title="Show the list of pages where the message could not be delivered.">Show skipped pages</a>'),
deliveredBox,
skippedBox
);
var pagesCountInfo = $('<div id="pages-count-info" style="margin-bottom:10px;margin-top:10px;padding:5px 0 5px 0;font-weight:bold;color:blue;display:none;"></div>')
.attr('title', 'Shows how many pages you will deliver to.');
frameContainer.append(
$('<p>').text('Enter list of pages (one per line):').css('font-weight', 'bold'),
pagesCountInfo,
pagesTextarea.$element.css({'margin-bottom': '15px'}),
$('<p>').text('Subject:').css('font-weight', 'bold'),
subjectInputField.$element,
$('<p>').text('Message:').css('font-weight', 'bold'),
messageTextarea.$element,
$('<p>').text('Edit summary:').css('font-weight', 'bold'),
summaryInputField.$element,
$('<div>').css('padding', '10px'),
$('<label>').append(skipDuplicateCheckbox.$element, ' Skip pages with the same section name already present'),
$('<div>').css('padding', '10px'),
$('<label>').append(
followRedirectsCheckbox.$element.css('margin-right', '5px'),
'Follow redirects'
),
$('<div>').css('padding', '10px'),
$('<label>').append(minorEditCheckbox.$element, ' Mark edits as minor'),
$('<div>').css('padding', '10px'),
$('<label>').append(createIfMissingCheckbox.$element, ' Create page if it does not exist'),
$('<div>').css('padding', '10px'),
$('<div>').append(visualPreviewButton.$element, startButton.$element, pauseResumeButton.$element, cancelButton.$element),
previewContainer,
'<br/>',
logContainer,
linksContainer
);
$('#mw-content-text').append(frameContainer);
function updatePagesCount() {
var lines = pagesTextarea.getValue().split("\n"), count = 0;
lines.forEach(function(page){ if(page.trim()) count++; });
if (count > 0) {
pagesCountInfo.text('You are about to send a message to ' + count + ' page(s).').show();
} else {
pagesCountInfo.hide();
}
}
pagesTextarea.on('change', updatePagesCount);
updatePagesCount();
function updatePreviewButtonState() {
var subject = subjectInputField.getValue().trim();
var message = messageTextarea.getValue().trim();
var canPreview = !!subject && !!message;
visualPreviewButton.setDisabled(!canPreview);
if (!canPreview) {
visualPreviewButton.$element.attr('title', 'Please fill required fields (subject and message) to preview.');
} else {
visualPreviewButton.$element.attr('title', 'Preview how your message will look.');
}
}
subjectInputField.on('change', updatePreviewButtonState);
messageTextarea.on('change', updatePreviewButtonState);
updatePreviewButtonState();
function makeWikiLink(title) {
var url = mw.util.getUrl(title.replace(/ /g, '_'));
return $('<a>')
.addClass('mml-log-link')
.attr({href: url, target: '_blank', rel: 'noopener'})
.text(title);
}
function makeDiffLink(revid, label) {
var url = mw.util.getUrl('Special:Diff/' + revid);
return $('<a>')
.addClass('mml-diff-link')
.attr({href: url, target: '_blank', rel: 'noopener'})
.text(label || '[diff]');
}
function addLogEntry(icon, message, color, pageTitle, revidForDiff, customHtml) {
var logEntry = $('<li>').addClass('mml-log-entry').css({ 'color': color });
logEntry.append(new OO.ui.IconWidget({ icon: icon, flags: ['progressive'] }).$element.css({ 'margin-right': '5px', 'vertical-align': 'middle' }));
if (customHtml) {
logEntry.append($('<span>').html(customHtml));
} else if (pageTitle) {
var pageLink = makeWikiLink(pageTitle)[0].outerHTML;
var msgHtml = message.replace(
new RegExp(pageTitle.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')),
pageLink
);
logEntry.append($('<span>').html(msgHtml));
if (revidForDiff) {
logEntry.append(makeDiffLink(revidForDiff));
}
} else {
logEntry.append($('<span>').text(message));
}
logContainer.append(logEntry).show();
setTimeout(function() {
logContainer.scrollTop(logContainer[0].scrollHeight);
}, 5);
if (typeof message === 'string' && message.match(/^Sleeping for \d+ seconds to avoid flooding recent changes/i)) {
setTimeout(function() {
logEntry.slideUp(600, function() { $(this).remove(); });
}, 5000);
}
}
function previewMessage() {
var subject = subjectInputField.getValue().trim(),
message = messageTextarea.getValue().trim(),
wikitext = '== ' + subject + ' ==\n' + message;
var previewBox = $('<div>').css({
'padding': '20px',
'margin': '25px 0',
'overflow': 'auto',
'width': pagesTextarea.$element.width(),
'min-height': '350px',
'max-height': '500px',
'font-family': 'inherit',
'font-size': '13px',
'box-sizing': 'border-box',
'border': '1px solid #ccc',
'background': '#fff'
});
previewContainer.empty()
.append($('<h2>').text("Message preview:"))
.append(previewBox)
.show();
new mw.Api().post({
action: 'parse',
text: wikitext,
title: 'Preview',
contentmodel: 'wikitext',
pst: true,
format: 'json'
}).done(function(data) {
previewBox.html(data.parse.text['*']);
$('html, body').animate({
scrollTop: previewContainer.offset().top
}, 500);
}).fail(function() {
previewBox.html('<p>Error loading preview</p>');
});
startButton.setDisabled(false);
}
function setPauseResumeState(paused) {
if(paused) {
pauseResumeButton.setLabel('Resume')
.setIcon(new OO.ui.IconWidget({icon: 'play', flags: ['progressive']}))
.setFlags(['progressive']);
} else {
pauseResumeButton.setLabel('Pause')
.setIcon(new OO.ui.IconWidget({icon: 'pause', flags: ['progressive']}))
.setFlags(['progressive']);
}
}
pauseResumeButton.on('click', function() {
isPaused = !isPaused;
setPauseResumeState(isPaused);
if (!isPaused && !operatorPausedByNewMessage && typeof window.currentProcessNextPage === "function") window.currentProcessNextPage();
});
function resolveRedirect(pageTitle) {
return new Promise(function(resolve, reject) {
if (followRedirectsCheckbox && !followRedirectsCheckbox.isSelected()) {
resolve(pageTitle);
return;
}
new mw.Api().get({
action: 'query',
titles: pageTitle,
redirects: 1
}).done(function(data) {
if (data.query && data.query.redirects && data.query.redirects.length > 0) {
resolve(data.query.redirects[0].to);
} else {
var pageId = Object.keys(data.query.pages)[0];
if (pageId === '-1') return resolve(pageTitle);
resolve(data.query.pages[pageId].title);
}
}).fail(function() {
resolve(pageTitle);
});
});
}
function getLastTalkPageRevId(callback) {
var userTalkPage = 'User talk:' + mw.config.get('wgUserName');
new mw.Api().get({
action: 'query',
prop: 'revisions',
titles: userTalkPage,
rvprop: 'ids|timestamp',
rvlimit: 1
}).done(function(data) {
var pageId = Object.keys(data.query.pages)[0];
if (pageId === '-1') return callback(null);
var rev = data.query.pages[pageId].revisions[0];
callback(rev.revid);
});
}
function checkTalkPageAndPauseIfNeeded(callback) {
var userTalkPage = 'User talk:' + mw.config.get('wgUserName');
new mw.Api().get({
action: 'query',
prop: 'revisions',
titles: userTalkPage,
rvprop: 'ids|timestamp',
rvlimit: 1
}).done(function(data) {
var pageId = Object.keys(data.query.pages)[0];
if (pageId === '-1') return callback(false);
var rev = data.query.pages[pageId].revisions[0];
if (lastTalkRevId === null) {
lastTalkRevId = rev.revid;
callback(false);
} else if (rev.revid !== lastTalkRevId) {
addLogEntry('alert', 'You have a new message on your talk page! Pausing delivery.', 'orange');
operatorPausedByNewMessage = true;
isPaused = true;
setPauseResumeState(true);
lastTalkRevId = rev.revid;
window.setTimeout(function() {
window.alert('There is a new message on your talk page. Please check it before continuing.');
}, 100);
callback(true);
} else {
callback(false);
}
});
}
function removePageFromTextarea(page) {
var lines = pagesTextarea.getValue().split("\n");
var filtered = lines.filter(function(line) { return line.trim() !== page; });
pagesTextarea.setValue(filtered.join("\n"));
updatePagesCount();
}
// Expand/collapse logic
linksContainer.on('click', '#show-delivered-list', function(e){
e.preventDefault();
if(deliveredBox.is(':visible')) {
deliveredBox.slideUp();
} else {
deliveredBox.find('textarea').val(deliveredPages.join('\n'));
deliveredBox.slideDown();
skippedBox.slideUp();
}
});
linksContainer.on('click', '#show-skipped-list', function(e){
e.preventDefault();
if(skippedBox.is(':visible')) {
skippedBox.slideUp();
} else {
skippedBox.find('textarea').val(skippedPages.join('\n'));
skippedBox.slideDown();
deliveredBox.slideUp();
}
});
function sendMessage() {
var pages = pagesTextarea.getValue().split("\n").map(function(page){return page.trim();}).filter(function(page){return page;}),
subject = subjectInputField.getValue().trim(),
message = messageTextarea.getValue().trim(),
summary = summaryInputField.getValue().trim() + " (using [[User:DreamRimmer/massMessageLite|massMessageLite]])",
wikitext = '== ' + subject + ' ==\n' + message,
skipDuplicate = skipDuplicateCheckbox.isSelected(),
minorEdit = minorEditCheckbox.isSelected(),
createIfMissing = createIfMissingCheckbox.isSelected(),
userGroups = mw.config.get('wgUserGroups'),
isSysop = userGroups.includes('sysop'),
maxMessagesPerMinute = isSysop ? 25 : 15,
sentMessages = 0,
startTime = new Date().getTime();
deliveredPages = [];
skippedPages = [];
deliveredDiffs = {};
linksContainer.hide();
deliveredBox.hide();
skippedBox.hide();
if (pages.length === 0 || subject === "" || message === "" || summary === "") {
alert("Error: Please fill in all fields");
return;
}
logContainer.empty().append($('<h2>').text("Delivery logs:")).css('margin-top', '5px');
logContainer.show();
var currentIndex = 0, processedPages = 0;
window.currentProcessNextPage = processNextPage;
function processNextPage() {
if (isPaused || operatorPausedByNewMessage) return;
if (currentIndex >= pages.length) {
pauseResumeButton.setDisabled(true);
showLinksIfAny();
return;
}
pauseResumeButton.setDisabled(false);
var page = pages[currentIndex];
resolveRedirect(page).then(function(resolvedPage) {
if (resolvedPage !== page && followRedirectsCheckbox.isSelected()) {
addLogEntry(
'articleRedirect',
'',
'blue',
null,
null,
makeWikiLink(page)[0].outerHTML + ' is a redirect. Using ' + makeWikiLink(resolvedPage)[0].outerHTML + '.'
);
}
page = resolvedPage;
new mw.Api().get({
action: 'query',
prop: 'revisions',
titles: page,
rvprop: 'content',
rvslots: '*'
}).done(function(data) {
var pageId = Object.keys(data.query.pages)[0];
if (pageId === '-1') {
if (createIfMissing) {
new mw.Api().postWithToken('csrf', {
action: 'edit',
title: page,
text: wikitext,
summary: summary,
minor: minorEdit ? true : undefined
}).done(function(editdata) {
var revid = editdata && editdata.edit && editdata.edit.newrevid ? editdata.edit.newrevid : null;
addLogEntry('message', 'Page created and messaged ' + page + '.', 'green', page, revid);
deliveredPages.push(page);
if (revid) deliveredDiffs[page] = revid;
removePageFromTextarea(pages[currentIndex]);
sentMessages++;
currentIndex++;
processedPages++;
afterPageProcessed();
}).fail(function() {
addLogEntry('alert', 'Failed to create ' + page + '.', 'red', page);
skippedPages.push(page);
removePageFromTextarea(pages[currentIndex]);
currentIndex++;
processedPages++;
afterPageProcessed();
});
} else {
addLogEntry('alert', 'Page ' + page + ' does not exist.', 'red', page);
skippedPages.push(page);
removePageFromTextarea(pages[currentIndex]);
currentIndex++;
processedPages++;
afterPageProcessed();
}
return;
}
var content = data.query.pages[pageId].revisions[0].slots.main['*'];
if (content.includes("{{User:DreamRimmer/NoMassMessage}}")) {
addLogEntry('alert', page + ' was skipped; (opted-out of message delivery)', 'red', page);
skippedPages.push(page);
removePageFromTextarea(pages[currentIndex]);
currentIndex++;
processedPages++;
afterPageProcessed();
return;
}
if (skipDuplicate && content.includes('== ' + subject + ' ==')) {
addLogEntry('alert', 'Message already exists on ' + page + '.', 'red', page);
skippedPages.push(page);
removePageFromTextarea(pages[currentIndex]);
currentIndex++;
processedPages++;
afterPageProcessed();
return;
}
var newContent = content + "\n\n" + wikitext;
new mw.Api().postWithToken('csrf', {
action: 'edit',
title: page,
text: newContent,
summary: summary,
minor: minorEdit ? true : undefined
}).done(function(editdata) {
var revid = editdata && editdata.edit && editdata.edit.newrevid ? editdata.edit.newrevid : null;
addLogEntry('message', 'Message sent to ' + page + '.', 'green', page, revid);
deliveredPages.push(page);
if (revid) deliveredDiffs[page] = revid;
removePageFromTextarea(pages[currentIndex]);
sentMessages++;
currentIndex++;
processedPages++;
afterPageProcessed();
}).fail(function() {
addLogEntry('alert', 'Failed to send message to ' + page + '.', 'red', page);
skippedPages.push(page);
removePageFromTextarea(pages[currentIndex]);
currentIndex++;
processedPages++;
afterPageProcessed();
});
}).fail(function() {
addLogEntry('alert', 'Failed to retrieve content of ' + page + '.', 'red', page);
skippedPages.push(page);
removePageFromTextarea(pages[currentIndex]);
currentIndex++;
processedPages++;
afterPageProcessed();
});
});
}
function afterPageProcessed() {
if (processedPages % 5 === 0 && processedPages > 0) {
checkTalkPageAndPauseIfNeeded(function(paused){
if (!paused) checkRateLimitAndContinue();
});
} else {
checkRateLimitAndContinue();
}
}
function checkRateLimitAndContinue() {
var currentTime = new Date().getTime(),
elapsedTime = (currentTime - startTime) / 1000,
maxMessages = maxMessagesPerMinute,
sleepTime = (60 / maxMessages) * sentMessages - elapsedTime;
if (sleepTime > 0) {
addLogEntry('clock', 'Sleeping for ' + Math.ceil(sleepTime) + ' seconds to avoid flooding recent changes...', 'blue');
setTimeout(processNextPage, sleepTime * 1000);
} else {
processNextPage();
}
}
function showLinksIfAny() {
if (deliveredPages.length > 0 || skippedPages.length > 0) {
linksContainer.show();
deliveredBox.hide();
skippedBox.hide();
}
}
getLastTalkPageRevId(function(revId){
lastTalkRevId = revId;
processNextPage();
});
$('html, body').animate({
scrollTop: logContainer.offset().top
}, 500);
}
visualPreviewButton.on('click', previewMessage);
startButton.on('click', function() {
isPaused = false;
operatorPausedByNewMessage = false;
setPauseResumeState(false);
pauseResumeButton.setDisabled(false);
sendMessage();
});
}
function checkUserAccess() {
var username = mw.config.get('wgUserName');
new mw.Api().get({
action: 'query',
titles: 'User:DreamRimmer/massmessage.json',
prop: 'revisions',
rvprop: 'content'
}).done(function(data) {
var pageId = Object.keys(data.query.pages)[0];
if (pageId === '-1') {
alert("Error: Cannot retrieve access control list");
window.location.href = mw.config.get('wgServer');
return;
}
var content = data.query.pages[pageId].revisions[0]['*'],
accessControl = JSON.parse(content);
if (accessControl.blockedUsers.includes(username)) {
alert("You are blocked from using this script. Please contact User:DreamRimmer for more details.");
window.location.href = mw.config.get('wgServer');
return;
}
if (accessControl.allowedUsers.includes(username)) {
initializeMassMessage();
} else {
var userGroups = mw.config.get('wgUserGroups');
if (userGroups.includes('extendedconfirmed') || userGroups.includes('sysop')) {
initializeMassMessage();
} else {
alert("You do not have permission to use this script. Please contact User:DreamRimmer.");
window.location.href = mw.config.get('wgServer');
}
}
}).fail(function() {
alert("Error: Cannot retrieve access control list. Please contact User:DreamRimmer");
window.location.href = mw.config.get('wgServer');
});
}
$.when(mw.loader.using('mediawiki.util'), $.ready).then(function() {
mw.util.addPortletLink(
'p-tb',
mw.util.getUrl('Special:BlankPage/massMessageLite'),
'massMessageLite'
);
});
if (mw.config.get('wgCanonicalSpecialPageName') === 'Blankpage' && mw.config.get('wgTitle').split('/', 2)[1] === 'massMessageLite') {
$.when(mw.loader.using('oojs-ui-core'), $.ready).then(function() {
checkUserAccess();
});
}
});
//</nowiki>