「利用者:Dragoniez/scripts/dragoLib.js」の版間の差分
表示
削除された内容 追加された内容
copyToClipboard should preserve line breaks |
バグ修正 (特別:差分/89748151) |
||
6行目: | 6行目: | ||
if (typeof dragoLib === 'undefined') var dragoLib = {}; |
if (typeof dragoLib === 'undefined') var dragoLib = {}; |
||
/*global mediaWiki, jQuery */ |
|||
(function() { // Create a function scope |
(function(mw, $) { // Create a function scope |
||
// ******************************** SYNCHRONOUS FUNCTIONS ******************************** |
// ******************************** SYNCHRONOUS FUNCTIONS ******************************** |
||
187行目: | 188行目: | ||
d.setDate(d.getDate() - subtract); |
d.setDate(d.getDate() - subtract); |
||
} |
} |
||
d.setDate(d.getDate() +2); |
|||
var sectionName; |
var sectionName; |
||
902行目: | 902行目: | ||
} |
} |
||
})(); |
})(mediaWiki, jQuery); |
||
//</nowiki> |
//</nowiki> |
2022年5月29日 (日) 09:11時点における版
/****************************************
* dragoLib: Versatile function library *
****************************************/
//<nowiki>
if (typeof dragoLib === 'undefined') var dragoLib = {};
/*global mediaWiki, jQuery */
(function(mw, $) { // Create a function scope
// ******************************** SYNCHRONOUS FUNCTIONS ********************************
/**
* Extract templates from wikitext
* @param {string} wikitext
* @param {string} [templateName] case-insensitive
* @returns {Array}
*/
dragoLib.findTemplates = function(wikitext, templateName) {
if (paramsMissing(arguments, 1)) throwError('findTemplates');
// Split the wikitext with '{{', the head delimiter of templates
const tempInnerContent = wikitext.split('{{'); // Note: tempInnerContent[0] is always an empty string or a string that has nothing to do with templates
const templates = []; // The array of extracted templates to return
// Extract templates from the wikitext
if (tempInnerContent.length === 0) { // If the wikitext has no tempalte in it
return templates; // Return an empty array
} else { // If the wikitext has some templates in it
const nest = []; // Stores the element number of tempInnerContent if the element involves nested templates
for (let i = 1; i < tempInnerContent.length; i++) { // Loop through all elements in tempInnerContent (except tempInnerContent[0])
let tempTailCnt = (tempInnerContent[i].match(/\}\}/g) || []).length; // The number of '}}' in the split segment
let temp = ''; // Temporary escape hatch for templates
if (tempTailCnt === 0) { // The split segment not having any '}}' means that it nests another template
nest.push(i); // Push the element number into the array
} else if (tempTailCnt === 1) { // The split segment itself is the whole inner content of one template
temp = '{{' + tempInnerContent[i].split('}}')[0] + '}}';
if ($.inArray(temp, templates) === -1) templates.push(temp);
} else if (tempTailCnt > 1) { // The split segment is part of more than one template (e.g. TL2|...}}...}} )
for (let j = 0; j < tempTailCnt; j++) { // Loop through all the nests
if (j === 0) { // The innermost template
temp = '{{' + tempInnerContent[i].split('}}')[j] + '}}'; // Same as when tempTailCnt === 1
if ($.inArray(temp, templates) === -1) templates.push(temp);
} else { // Nesting templates
const elNum = nest[nest.length -1]; // The start of the nesting template
nest.pop();
const nestedTempInnerContent = tempInnerContent[i].split('}}');
temp = '{{' + tempInnerContent.slice(elNum, i).join('{{') + '{{' + nestedTempInnerContent.slice(0, j + 1).join('}}') + '}}';
if ($.inArray(temp, templates) === -1) templates.push(temp);
}
}
}
}
// Check if the optional parameter is specified
if (templateName && templates.length !== 0) {
const templateRegExp = new RegExp(templateName, 'i');
for (let i = templates.length -1; i >= 0; i--) {
// Remove the template from the array if it's not an instance of the specified template
if (templates[i].split('|')[0].search(templateRegExp) === -1) templates.splice(i, 1);
}
}
return templates;
}
};
/**
* Check if the current user belongs to a given user group
* @param {string} group
* @returns {boolean}
*/
dragoLib.inGroup = function(group) {
if (paramsMissing(arguments, 1)) throwError('inGroup');
return $.inArray(group, mw.config.get('wgUserGroups')) !== -1;
};
/**
* Check if the current user belongs to a given global user group
* @param {string} group
* @returns {boolean}
*/
dragoLib.inGlobalGroup = function(group) {
if (paramsMissing(arguments, 1)) throwError('inGlobalGroup');
return mw.config.exists('wgGlobalGroups') && $.inArray(group, mw.config.get('wgGlobalGroups')) !== -1;
};
/**
* Get the key of a value in an object
* @param {Object} object
* @param {*} value
* @returns {*} key
*/
dragoLib.getKeyByValue = function(object, value) {
if (paramsMissing(arguments, 2)) throwError('getKeyByValue');
for (let key in object) {
if (object[key] == value) return key;
}
};
/**
* Copy a string to the clipboard
* @param {string} str
*/
dragoLib.copyToClipboard = function(str) {
if (paramsMissing(arguments, 1)) throwError('copyToClipboard');
const $temp = $('<textarea>');
$('body').append($temp); // Create a temporarily hidden text field
$temp.val(str).select(); // Copy the text string into the field and select the text
document.execCommand('copy'); // Copy it to the clipboard
$temp.remove(); // Remove the text field
};
/**
* Add, remove, or move a loading spinner
* @param {string} action 'add', 'remove', or 'move'
*/
dragoLib.toggleLoadingSpinner = function(action) {
if (paramsMissing(arguments, 1)) throwError('toggleLoadingSpinner');
if ($.inArray(action, ['add', 'remove', 'move']) === -1) throwInvalidParamError('toggleLoadingSpinner', action);
const img = '<img class="dragolib-loading-spinner" src="https://upload.wikimedia.org/wikipedia/commons/4/42/Loading.gif" ' +
'style="vertical-align: middle; max-height: 100%; border: 0;">';
switch(action) {
case 'add':
return img;
case 'remove':
$('.dragolib-loading-spinner').remove();
return '';
case 'move':
$('.dragolib-loading-spinner').remove();
return img;
}
};
// Get today's date in the form of MM月DD日
dragoLib.today = function() {
const d = new Date();
return d.getMonth() + 1 + '月' + d.getDate() + '日';
};
/**
* Get the last day of a given month
* @param {number} year
* @param {number} month
* @returns {number}
*/
dragoLib.lastDay = function(year, month) {
if (paramsMissing(arguments, 2)) throwError('lastDay');
return new Date(year, month, 0).getDate();
};
/**
* Get 'YYYY年MM月D1日 - D2日新規XX', corresponding to the current date
* @param {string} suffix The XX part
* @param {boolean} [last] If true, go back 5 days (get the name of the preceding section)
* @returns {string} section name
*/
dragoLib.getSection5 = function(suffix, last) {
if (paramsMissing(arguments, 1)) throwError('getSection5');
const d = new Date();
if (last) {
let subtract = 5;
if (d.getDate() === 1 || d.getDate() === 2) {
subtract = 3;
} else if (d.getDate() === 31) {
subtract = 6;
}
d.setDate(d.getDate() - subtract);
}
var sectionName;
switch(true) {
case (1 <= d.getDate() && d.getDate() <= 5):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月1日 - 5日新規${suffix}`;
break;
case (6 <= d.getDate() && d.getDate() <= 10):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月6日 - 10日新規${suffix}`;
break;
case (11 <= d.getDate() && d.getDate() <= 15):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月11日 - 15日新規${suffix}`;
break;
case (16 <= d.getDate() && d.getDate() <= 20):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月16日 - 20日新規${suffix}`;
break;
case (21 <= d.getDate() && d.getDate() <= 25):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月21日 - 25日新規${suffix}`;
break;
case (26 <= d.getDate() && d.getDate() <= dragoLib.lastDay(d.getFullYear(), d.getMonth() + 1)):
sectionName = `${d.getFullYear()}年${d.getMonth() + 1}月26日 - ${dragoLib.lastDay(d.getFullYear(), d.getMonth() + 1)}日新規${suffix}`;
break;
default:
}
return sectionName;
};
/**
* Center a jQuery UI dialog (jQuery UI must be loaded)
* @param {string} selectorName
*/
dragoLib.centerDialog = function(selectorName) {
if (paramsMissing(arguments, 1)) throwError('centerDialog');
$(selectorName).dialog({'position': {my: 'center', at: 'center', of: window}});
};
/**
* Change the CSS of a jQuery UI dialog (jQuery UI must be loaded)
* @param {string} headerColor
* @param {string} backgroundColor
* @param {string|number} [fontSize]
*/
dragoLib.dialogCSS = function(headerColor, backgroundColor, fontSize) {
if (paramsMissing(arguments, 2)) throwError('dialogCSS');
$('.ui-dialog-content, .ui-dialog-buttonpane, .ui-corner-all, .ui-draggable, .ui-resizable').css('background', backgroundColor);
$('.ui-button').css({
'color': 'black',
'background-color': 'white'
});
$('.ui-dialog-titlebar, .ui-dialog-titlebar-close').attr('style', `background: ${headerColor} !important;`);
if (fontSize) $('.ui-dialog').css('font-size', fontSize);
};
/**
* Get rid of U+200E spaces from a string and trim it
* @param {string} str
* @returns {string}
*/
dragoLib.trim2 = function(str) {
if (paramsMissing(arguments, 1)) throwError('trim2');
return str.replace(/\u200e/g, '').trim();
};
/**
* Replace all occurences of a string with another
* @param {string} str source string
* @returns {string}
*/
dragoLib.replaceAll2 = function(str) { // Takes a replacee and a replacer (iterable)
if (paramsMissing(arguments, 3)) throwError('replaceAll2');
if (arguments.length %2 !== 1) {
throw 'ReferenceError: dragoLib.replaceAll2 takes an odd number of arguments.';
} else {
for (let i = 1; i < arguments.length; i += 2) {
str = str.split(arguments[i]).join(arguments[i + 1]);
}
return str;
}
};
/**
* Escape regular expressions
* @param {string} str
* @param {boolean} escapePipes
* @returns {string}
*/
dragoLib.escapeRegExp = function(str, escapePipes) {
if (paramsMissing(arguments, 1)) throwError('escapeRegExp');
if (typeof str !== 'string') throwTypeError('escapeRegExp', 'String');
const rep = ['\\', '(', ')', '{', '}', '.', '?', '!', '*', '+', '-', '^', '$', '[', ']'];
if (escapePipes) rep.push('|');
for (i = 0; i < rep.length; i++) {
str = str.split(rep[i]).join('\\' + rep[i]);
}
return str;
};
// ******************************** ASYNCHRONOUS FUNCTIONS ********************************
/**
* Get the timestamps of the latest revision and the current time
* @param {string} pagename
* @returns {Promise<{baseTS: string, curTS: string}>}
*/
dragoLib.getTimestamps = function(pagename) {
if (paramsMissing(arguments, 1)) throwError('getTimestamps');
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'query',
'titles': pagename,
'prop': 'revisions',
'curtimestamp': true,
'formatversion': 2
}).then(function(res){
var resPages;
if (res && res.query && (resPages = res.query.pages)) {
return resolve({
'baseTS': resPages[0].revisions[0].timestamp,
'curTS': res.curtimestamp
});
}
resolve();
}).catch(function() {
resolve();
});
});
};
/**
* Parse a page and get its content as wikitext and section info as an array
* @param {string} pagename
* @param {string|Array} [sectionTitles]
* @returns {Promise<{wikitext: string|Array, sections: Array, sectionNumber: string}>} wikitext is a string of the whole page if sectionTitles isn't specified,
* or else an array. sectionNumber is a number converted from the FIRST element in sectionTitles.
*/
dragoLib.parsePage = function(pagename, sectionTitles) {
if (paramsMissing(arguments, 1)) throwError('parsePage');
if (typeof sectionTitles === 'string') sectionTitles = [sectionTitles];
// API request
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'parse',
'page': pagename,
'prop': 'wikitext|sections',
'disablelimitreport': 1,
'disableeditsection': 1,
'formatversion': 2
}).then(function(res) {
var wikitext, sections, sectionNumber;
if (res && res.parse) {
wikitext = res.parse.wikitext;
sections = res.parse.sections;
if (sectionTitles) { // If section titles have been passed as a parameter
const allSectionTitles = [];
const sectionHeaders = ['']; // Array of equal-enclosed section headers (e.g. == SECTION ==) (Note: the top section has no header, thus arr[0] = '')
// Get section titles and their corresponding equal-enclosed wikitext
for (let i = 0; i < sections.length; i++) {
const section = sections[i];
if (section.line === sectionTitles[0] && !sectionNumber) sectionNumber = section.index; // Get section number if conditions are met
if (section.index.indexOf('T') === -1) { // If the section isn't a transcluded one
allSectionTitles.push(section.line); // Get the title of the section
if (section.level == 2) { // Get equal-enclosed section headers
sectionHeaders.push('== ' + section.line + ' ==');
} else if (section.level == 3) {
sectionHeaders.push('=== ' + section.line + ' ===');
} else if (section.level == 4) {
sectionHeaders.push('==== ' + section.line + ' ====');
} else if (section.level == 5) {
sectionHeaders.push('===== ' + section.line + ' =====');
}
}
}
// Separate the content of the parsed page into the content of each section
var sectionRegExp = new RegExp(`={2,5}\\s*(?:${dragoLib.escapeRegExp(allSectionTitles.join('|'))})\\s*={2,5}`, 'g');
var sectionContent = wikitext.split(sectionRegExp); // Array of the content of each section, without section headers
for (let i = 0; i < sectionContent.length; i++) { // Re-add to sectionContent the '== TITLE ==' header that's been removed by the split() above
sectionContent[i] = sectionHeaders[i] + sectionContent[i];
}
// Remove the contents of irrelevant sections from the array 'sectionContent'
sectionRegExp = new RegExp(`={2,5}\\s*(?:${dragoLib.escapeRegExp(sectionTitles.join('|'))})\\s*={2,5}`, 'g');
for (let i = sectionContent.length -1; i >= 0; i--) {
if (sectionContent[i].search(sectionRegExp) === -1) sectionContent.splice(i, 1);
}
}
return resolve({
'wikitext': sectionContent ? sectionContent : wikitext,
'sections': sections,
'sectionNumber': sectionNumber // Only the first match (Note: This is a string, not a number)
});
}
resolve();
}).catch(function() {
resolve();
});
});
};
/**
* Edit a given page
* @param {string} pagename
* @param {string} text
* @param {string} inserttype 'prependtext', 'appendtext', 'text'
* @param {string} basetimestamp
* @param {string} starttimestamp
* @param {string|number} [sectionnumber]
* @param {string} [summary]
* @param {string} [token] Give e.g. '' or something when you want to cause an intentional error
* @returns {Promise<boolean|string>} true when edit succeeded, false when an unknown error occurred, errcode when a known error occurred
*/
dragoLib.editPage = function(pagename, text, inserttype, basetimestamp, starttimestamp, sectionnumber, summary, token) {
if (paramsMissing(arguments, 5)) throwError('editPage');
return new Promise(function(resolve) {
const params = {
'action': 'edit',
'title': pagename,
'basetimestamp': basetimestamp,
'starttimestamp': starttimestamp,
'token': typeof token === 'undefined' ? mw.user.tokens.get('csrfToken') : token,
'format': 'json'
};
if ($.inArray(inserttype, ['text', 'appendtext', 'prependtext']) === -1) throwInvalidParamError('editPage', inserttype);
params[inserttype] = text;
if (typeof sectionnumber !== 'undefined') params.section = sectionnumber;
if (typeof summary !== 'undefined') params.summary = summary;
new mw.Api().post(params).then(function(res) {
if (res && res.edit) {
if (res.edit.result === 'Success') return resolve(true);
}
resolve(false);
}).catch(function(code, err) {
resolve(err.error.info);
});
});
};
/**
* Check if a user exists locally
* @param {string} username
* @returns {Promise<boolean>}
*/
dragoLib.userExists = function(username) {
if (paramsMissing(arguments, 1)) throwError('userExists');
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'query',
'list': 'users',
'ususers': username,
'formatversion': 2
}).then(function(res){
resolve(res.query.users[0].userid !== undefined); // True if the user exists and false if not
}).catch(function() {
resolve();
});
});
};
/**
* Convert wikitext to html
* @param {string} wikitext
* @param {string} [wikisummary]
* @returns {Promise<{htmltext: string, htmlsummary: string}>}
*/
dragoLib.getParsedHtml = function(wikitext, wikisummary) {
if (paramsMissing(arguments, 1)) throwError('getParsedHtml');
return new Promise(function(resolve) {
new mw.Api().post({
'action': 'parse',
'text': wikitext,
'summary': typeof wikisummary === 'undefined' ? '' : wikisummary,
'contentmodel': 'wikitext',
'prop': 'text',
'disableeditsection': true,
'formatversion': 2
}).then(function(res) {
if (res && res.parse) {
return resolve({
'htmltext': res.parse.text,
'htmlsummary': res.parse.parsedsummary
});
}
resolve();
}).catch(function(code, err) {
console.log(err.error.info);
resolve();
});
});
};
/**
* Watch pages
* @param {Array} pagesArr
* @returns {Array} Array of watched pages (returns undefined if watchtoken failed to be fetched)
*/
dragoLib.watchPages = function(pagesArr) {
const pgArr = JSON.parse(JSON.stringify(pagesArr)); // Prevent pass-by-reference (the variable will be spliced)
if (paramsMissing(arguments, 1)) throwError('watchPages');
if (!Array.isArray(pgArr)) throwTypeError('watchPages', 'Array');
if (pgArr.length === 0) {
console.log('dragoLib.watchPages: The passed array is empty.');
return [];
}
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'query',
'meta': 'tokens',
'type': 'watch',
'format': 'json'
}).then(async function(res){
var token, watchAsync = [];
if (!res || !res.query || !(token = res.query.tokens)) {
mw.log.error('dragoLib.watchPages: Failed to get a watchtoken.');
return resolve();
} else {
token = token.watchtoken;
}
while(pgArr.length !== 0) {
watchAsync.push(addToWatchlist(pgArr.slice(0, 50), token));
pgArr.splice(0, 50);
}
const result = await Promise.all(watchAsync);
resolve([].concat.apply([], result));
}).catch(function(){
mw.log.error('dragoLib.watchPages: Failed to get a watchtoken.');
resolve();
});
});
/**
* @param {Array} pages
* @param {string} token
* @returns {Promise<Array>}
*/
function addToWatchlist(pages, token) {
return new Promise(function(resolve) {
new mw.Api().post({
'action': 'watch',
'titles': pages.join('|'),
'token': token,
'formatversion': 2
}).then(function(res) {
const watched = [];
if (res) {
for (let i = 0; i < res.watch.length; i++) {
if (res.watch[i].watched == true) watched.push(res.watch[i].title);
}
} else {
mw.log.warn('dragoLib.watchPages: Unexpected error occurred on a watch-pages attempt.');
}
resolve(watched);
}).catch(function(code, err) {
mw.log.warn('dragoLib.watchPages: Error occurred on a watch-pages attempt: ' + err.error.info);
resolve([]);
});
});
}
};
/**
* Get an array of users and IPs that are banned from editing (in any way) from an array of random users and IPs
* @param {Array} namesArr
* @returns
*/
dragoLib.getRestricted = async function(namesArr) {
if (paramsMissing(arguments, 1)) throwError('getRestricted');
if (!Array.isArray(namesArr)) throwTypeError('getRestricted', 'Array');
if (namesArr.length === 0) {
console.log('dragoLib.getRestricted: The passed array is empty.');
return [];
}
// Check the local block status of all names in the array
var restricted = await dragoLib.getBlockedUsers(namesArr);
namesArr = namesArr.filter(function(name) { // Remove elements in namesArr that are also in restricted
return restricted.indexOf(name) < 0;
});
if (namesArr.length === 0) return restricted;
// Check the rest of the names
const users = [], ips = [];
for (let i = 0; i < namesArr.length; i++) { // Sort names to users and IPs
if (mw.util.isIPAddress(namesArr[i], true)) {
ips.push(namesArr[i]);
} else {
users.push(namesArr[i]);
}
}
if (users.length !== 0 && ips.length !== 0) {
restricted = restricted.concat(await dragoLib.getBlockedIps(ips), await dragoLib.getLockedUsers(users), await dragoLib.getGloballyBlockedIps(ips));
} else if (users.length !== 0) {
restricted = restricted.concat(await dragoLib.getLockedUsers(users));
} else if (ips.length !== 0) {
restricted = restricted.concat(await dragoLib.getBlockedIps(ips), await dragoLib.getGloballyBlockedIps(ips));
}
restricted = restricted.filter(function(element, index) { // Remove duplicates
return restricted.indexOf(element) === index;
});
return restricted;
};
/**
* Get an array of blocked users from an array of users and IPs (Note: This function does not detect single IPs in blocked ranges)
* @param {Array} usersArr
* @returns {Promise<Array>}
*/
dragoLib.getBlockedUsers = function(usersArr) {
const users = JSON.parse(JSON.stringify(usersArr)); // Prevent pass-by-reference (the variable will be spliced)
if (paramsMissing(arguments, 1)) throwError('getBlockedUsers');
if (!Array.isArray(users)) throwTypeError('getBlockedUsers', 'Array');
if (users.length === 0) {
console.log('dragoLib.getBlockedUsers: The passed array is empty.');
return [];
}
return new Promise(async function(resolve) {
const blockedAsync = [];
while(users.length !== 0) {
blockedAsync.push(gbApiQuery(users.slice(0, 50)));
users.splice(0, 50);
}
const result = await Promise.all(blockedAsync);
resolve([].concat.apply([], result));
});
/**
* @param {Array} arr
* @returns {Array}
*/
function gbApiQuery(arr) {
return new Promise(function(resolve) {
new mw.Api().post({
'action': 'query',
'list': 'blocks',
'bklimit': 50,
'bkusers': arr.join('|'),
'bkprop': 'user',
'formatversion': 2
}).then(function(res) {
const blocked = [];
var resBlk;
if (res && (resBlk = res.query)) {
if ((resBlk = resBlk.blocks).length !== 0) {
for (let i = 0; i < resBlk.length; i++) {
blocked.push(resBlk[i].user); // Push blocked users into the array
}
}
} else {
mw.log.warn('dragoLib.getBlockedUsers: Unexpected error occurred on a check-blocks attempt.');
}
resolve(blocked);
}).catch(function(code, err) {
mw.log.warn('dragoLib.getBlockedUsers: Error occurred on a check-blocks attempt: ' + err.error.info);
resolve([]);
});
});
}
};
/**
* Check if a user is locally blocked
* @param {string} user Can be any of a registered user, an IP, and an IP range
* @returns {Promise<boolean>}
*/
dragoLib.isBlocked = function(user) {
if (paramsMissing(arguments, 1)) throwError('isBlocked');
if (typeof user !== 'string') throwTypeError('isBlocked', 'String');
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'query',
'list': 'blocks',
'bklimit': 1,
'bkusers': user,
'bkprop': 'user',
'formatversion': 2
}).then(function(res) {
if (res && res.query) {
resolve(res.query.blocks.length !== 0);
} else {
mw.log.error('dragoLib.isBlocked: Unexpected error occurred on a check-block attempt.');
resolve();
}
}).catch(function(code, err) {
mw.log.error('dragoLib.isBlocked: Error occurred on a check-block attempt: ' + err.error.info);
resolve();
});
});
};
/**
* Get an array of locked users from an array of registered users
* @param {Array} regUsersArr
* @returns {Promise<Array>}
*/
dragoLib.getLockedUsers = function(regUsersArr) {
if (paramsMissing(arguments, 1)) throwError('getLockedUsers');
if (!Array.isArray(regUsersArr)) throwTypeError('getLockedUsers', 'Array');
if (regUsersArr.length === 0) {
console.log('dragoLib.getLockedUsers: The passed array is empty.');
return [];
}
return new Promise(async function(resolve) {
const lockedAsync = [], lockedUsers = [];
for (let i = 0; i < regUsersArr.length; i++) {
lockedAsync.push(dragoLib.isLocked(regUsersArr[i]).then(function(locked) {
if (locked) lockedUsers.push(regUsersArr[i]);
}));
}
await Promise.all(lockedAsync);
resolve(lockedUsers);
});
};
/**
* Check if a user is globally locked
* @param {string} user
* @returns {Promise<boolean>}
*/
dragoLib.isLocked = function(user) {
if (paramsMissing(arguments, 1)) throwError('isLocked');
if (typeof user !== 'string') throwTypeError('isLocked', 'String');
return new Promise(function(resolve) {
new mw.Api().get({
action: 'query',
list: 'globalallusers',
agulimit: 1,
agufrom: user,
aguto: user,
aguprop: 'lockinfo'
}).then(function(res) {
var resLck;
if (res && res.query && (resLck = res.query.globalallusers)) {
resolve(resLck.length === 0 ? false : resLck[0].locked !== undefined); // resLck[0].locked === '' if locked, otherwise undefined
} else {
mw.log.error('dragoLib.isLocked: Unexpected error occurred on a check-lock attempt.');
resolve();
}
}).catch(function(code, err) {
mw.log.error('dragoLib.isLocked: Error occurred on a check-lock attempt: ' + err.error.info);
resolve();
});
});
};
/**
* Get an array of locally blocked IPs from an array of random IPs (can detect range blocks)
* @param {Array} ipsArr
* @returns {Promise<Array>}
*/
dragoLib.getBlockedIps = function(ipsArr) {
if (paramsMissing(arguments, 1)) throwError('getBlockedIps');
if (!Array.isArray(ipsArr)) throwTypeError('getBlockedIps', 'Array');
if (ipsArr.length === 0) {
console.log('dragoLib.getBlockedIps: The passed array is empty.');
return [];
}
return new Promise(async function(resolve) {
const blockedAsync = [], blockedIps = [];
for (let i = 0; i < ipsArr.length; i++) {
blockedAsync.push(dragoLib.isIpBlocked(ipsArr[i]).then(function(blocked) {
if (blocked) blockedIps.push(ipsArr[i]);
}));
}
await Promise.all(blockedAsync);
resolve(blockedIps);
});
};
/**
* Check if a given IP is locally blocked (can detect range blocks)
* @param {string} ip
* @returns {Promise<boolean>}
*/
dragoLib.isIpBlocked = function(ip) {
if (paramsMissing(arguments, 1)) throwError('isIpBlocked');
if (typeof ip !== 'string') throwTypeError('isIpBlocked', 'String');
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'query',
'list': 'blocks',
'bklimit': 1,
'bkip': ip,
'bkprop': 'user',
'formatversion': 2
}).then(function(res) {
if (res && res.query) {
resolve(res.query.blocks.length !== 0);
} else {
mw.log.error('dragoLib.isIpBlocked: Unexpected error occurred on a check-block attempt.');
resolve();
}
}).catch(function(code, err) {
mw.log.error('dragoLib.isIpBlocked: Error occurred on a check-block attempt: ' + err.error.info);
resolve();
});
});
};
/**
* Function to get an array of globally blocked IPs from an array of random IPs
* @param {Array} ipsArr
* @returns {Promise<Array>}
*/
dragoLib.getGloballyBlockedIps = function(ipsArr) {
if (paramsMissing(arguments, 1)) throwError('getGloballyBlockedIps');
if (!Array.isArray(ipsArr)) throwTypeError('getGloballyBlockedIps', 'Array');
if (ipsArr.length === 0) {
console.log('dragoLib.getGloballyBlockedIps: The passed array is empty.');
return [];
}
return new Promise(async function(resolve) {
const blockedAsync = [], blockedIps = [];
for (let i = 0; i < ipsArr.length; i++) {
blockedAsync.push(dragoLib.isIpGloballyBlocked(ipsArr[i]).then(function(blocked) {
if (blocked) blockedIps.push(ipsArr[i]);
}));
}
await Promise.all(blockedAsync);
resolve(blockedIps);
});
};
/**
* Check if a given IP is globally blocked (can detect range blocks)
* @param {string} ip
* @returns {Promise<boolean>}
*/
dragoLib.isIpGloballyBlocked = function(ip) {
if (paramsMissing(arguments, 1)) throwError('isIpGloballyBlocked');
if (typeof ip !== 'string') throwTypeError('isIpGloballyBlocked', 'String');
return new Promise(function(resolve) {
new mw.Api().get({
'action': 'query',
'list': 'globalblocks',
'bgip': ip,
'bglimit': 1,
'bgprop': 'address',
'formatversion': 2
}).then(function(res) {
if (res && res.query) {
resolve(res.query.globalblocks.length !== 0);
} else {
mw.log.error('dragoLib.isIpGloballyBlocked: Unexpected error occurred on a check-block attempt.');
resolve();
}
}).catch(function(code, err) {
mw.log.error('dragoLib.isIpGloballyBlocked: Error occurred on a check-block attempt: ' + err.error.info);
resolve();
});
});
};
// ******************************** LIBRARY FUNCTIONS ********************************
// The following functions are for the library itself and not included in dragoLib
/**
* @param {*} args Always pass 'arguments'
* @param {number} stopAt Number of necessary parameters (all optional parameters should follow necessary parameters)
* @returns {boolean}
*/
function paramsMissing(args, stopAt) {
for (let i = 0; i < stopAt; i++) {
if (typeof args[i] === 'undefined') return true;
}
return false;
}
/**
* @param {string} functionName
*/
function throwError(functionName) {
throw mw.log.error(`Uncaught ReferenceError: Necessary parameter(s) not set. (dragoLib.${functionName})`);
}
/**
* @param {string} functionName
* @param {*} param
*/
function throwInvalidParamError(functionName, param) {
throw mw.log.error(`Uncaught ReferenceError: ${param} is an invalid parameter. (dragoLib.${functionName})`);
}
/**
* @param {string} functionName
* @param {string} type
*/
function throwTypeError(functionName, type) {
throw mw.log.error(`Uncaught TypeError: ${type} must be passed to dragoLib.${functionName}.`);
}
})(mediaWiki, jQuery);
//</nowiki>