// Script to Modernize [[Special:NewPages]];
// Developed by [[User:Jeeputer]] and [[User:WASP-Outis]]
$.when(mw.loader.using([
'mediawiki.api',
'mediawiki.util',
'oojs-ui-core',
'oojs-ui-widgets',
'oojs-ui.styles.icons-editing-advanced',
'oojs-ui.styles.icons-editing-list',
'oojs-ui.styles.icons-accessibility',
'oojs-ui.styles.icons-editing-citation',
'oojs-ui.styles.icons-moderation']), $.ready)
.then(function() {
if (mw.config.get('wgCanonicalSpecialPageName') !== "Newpages") return;
mw.loader.load('https://fa.wikipedia.org/w/index.php?title=User:Jeeputer/newPagesFeed.css&action=raw&ctype=text/css', 'text/css');
var api = new mw.Api();
// To search for "<ref>" tags in text of each article
function checkRefs(text) {
var out = /(class=\"reference-text|id=\"cite_note|مشارکتکنندگان ویکیپدیا)/g.test(text) ? '' : ' • فاقد منبع';
return out;
}
function checkRecreate(tags) // check if page is recreated
{
for(var i = 0; i < tags.length; i++)
{
var out = /ایجاد دوبارهٔ صفحهٔ حذف شده/g.test(tags[i][0].innerHTML);
return out;
}
}
function liftWing(requirements) {
var inferenceUrl = "https://api.wikimedia.org/service/lw/inference/v1/models/fawiki-damaging:predict";
let headers = new Headers({
"Content-Type": "application/json"
});
let liftWingData = {"rev_id": Number(requirements.id)};
fetch(inferenceUrl, {
method: "POST",
headers: headers,
body: JSON.stringify(liftWingData)
}).then(
response => response.json()
).then(
inferenceData => {
var DamagingScore = inferenceData.fawiki.scores[requirements.id].damaging.score.probability.true; // Liftwing Score
function isDisambiguation()
{
for (var c = 0; c < requirements.cats.length; c++) {
var catName = requirements.cats[c]['*'];
if(catName === 'صفحههای_ابهامزدایی')
{
return true;
}
}
}
if(!isDisambiguation())
{
if (requirements.ref != '') { // refrences Score
DamagingScore = DamagingScore + 0.85;
}
if (requirements.patrol && !requirements.csd) { // Patrolled and there's no csd tag
DamagingScore = DamagingScore - 0.3;
}
if(requirements.tags && checkRecreate(requirements.tags) || requirements.referror) // page is recreated OR refs have error
{
DamagingScore = DamagingScore + 0.3;
}
}
if (DamagingScore > 0.5) {
$('#npf-ores-' + requirements.id)
.addClass('npf-ores-high')
.css('color', 'red')
.attr('title', 'احتمال خرابکاری زیاد (' + (DamagingScore * 100).toPrecision(4) + '٪)')
.show();
$('#npf-box-' + requirements.revid).attr('data-ores', "3"); // add data attr for filtering
}
else if (DamagingScore <= 0.5 && DamagingScore >= 0.11) {
$('#npf-ores-' + requirements.id)
.addClass('npf-ores-average')
.css('color', 'orange')
.attr('title', 'احتمال خرابکاری متوسط (' + (DamagingScore * 100).toPrecision(4) + '٪)')
.show();
$('#npf-box-' + requirements.revid).attr('data-ores', "2"); // add data attr for filtering
}
else if (DamagingScore < 0.11) {
$('#npf-ores-' + requirements.id)
.addClass('npf-ores-low')
.css('color', 'green')
.attr('title', 'احتمال خرابکاری کم (' + (DamagingScore * 100).toPrecision(4) + '٪)')
.show();
$('#npf-box-' + requirements.revid).attr('data-ores', "1"); // add data attr for filtering
}
}
);
}
function parsePage(ingredients) {
return api.get({
action: 'parse',
oldid: ingredients.revid,
format: 'json'
}).done(function(data) {
var refTest = checkRefs(data.parse.text["*"]);
var refErrorTest = /خطای یادکرد:/g.test(data.parse.text["*"]);
var cats = data.parse.categories;
var liftWingRequirements = {
csd: false,
ref: refTest,
referror: refErrorTest,
patrol: !ingredients.notPatrolled,
id: ingredients.firstrevid,
tags: ingredients.tags,
title: ingredients.title,
cats: cats,
revid: ingredients.revid
};
for (var c = 0; c < cats.length; c++) {
var catName = cats[c]['*'];
if (catName === 'مقالههای_نامزد_حذف_سریع') {
var $csdElement = $('<span id="npf-csd-' + ingredients.revid + '">')
.attr('title', 'این صفحه نامزد حذف سریع شده است')
.css({
'display': 'none',
'width': '150px'
})
.addClass('npf-row-content-left npf-csd')
.text('نامزد حذف سریع');
$('div#npf-comment-' + ingredients.revid).append($csdElement);
liftWingRequirements.csd = true;
$csdElement.toggle(2000);
} else if (catName === 'صفحههای_حذف_زماندار') {
var $prodElement = $('<span>')
.attr('title', 'این صفحه نامزد حذف زماندار شده است')
.css('display', 'none')
.addClass('npf-row-content-left npf-csd')
.text('نامزد حذف زماندار');
$('div#npf-comment-' + ingredients.revid).append($prodElement);
$prodElement.toggle(2000);
} else if (catName === 'مقالههای_نامزد_حذف') {
var afdUrl = $(data.parse.text['*']).find('a:contains("نظرخواهی مربوط به این صفحه")')[0].href;
var $afdElement = $('<a>')
.attr({
'title': 'این صفحه در نظرخواهی برای حذف نامزد است',
'href': afdUrl
})
.css('display', 'none')
.addClass('npf-row-content-left npf-afd')
.text('نظرخواهی برای حذف');
$('div#npf-comment-' + ingredients.revid).append($afdElement);
$afdElement.toggle(2000);
}
}
// Evaluate Lift Wing data
liftWing(liftWingRequirements);
var contentCats = cats.filter(function(cat) {
return typeof(cat.hidden) !== "string";
});
var langlinks = data.parse.langlinks || 0;
var enLangLink = false;
if (langlinks) {
for (var li = 0; li < langlinks.length; li++) {
if (langlinks[li].lang === 'en') {
// [ url, English title ]
enLangLink = [langlinks[li].url, langlinks[li]['*']];
break;
}
}
}
var categoriesCount = contentCats.length ? mw.language.convertNumber(contentCats.length) : 'فاقد';
var langLinksCount = langlinks.length ? mw.language.convertNumber(langlinks.length) : 'فاقد';
// Replace "در حال تجزیهٔ صفحه…" with categories and langlinks count
$('#cat-iw-container-' + ingredients.revid).fadeOut(
1000,
function() {
$('#cat-iw-container-' + ingredients.revid).empty();
$('#cat-iw-container-' + ingredients.revid)
.attr('title', 'اطلاعات ردهها و میانویکیها')
.append(
'<span id="npf-cat-count-' + ingredients.revid + '">' + categoriesCount + ' رده</span> • ' +
'<span' + (langLinksCount === 'فاقد' ? ' class="npf-noIW">' : '>') + langLinksCount + ' میانویکی</span>' +
// Append English language link if exists
(enLangLink
? ' (<a href="' + enLangLink[0] + '" title="' + enLangLink[1] + '">en</a>)'
: ''
) +
'<span id="npf-ref-existenz-' + ingredients.revid + '"' +
(refTest === '' ? '>' : ' class="npf-norefs">') + refTest + '</span>'
);
// Font color = red if we have no categories
if (contentCats.length < 1) $('#npf-cat-count-' + ingredients.revid).addClass('npf-nocat');
// add data attr for filtering
if(langLinksCount === 'فاقد')
{
$('#npf-box-' + ingredients.revid).attr('data-langlinks', "0");
}
if(categoriesCount === 'فاقد')
{
$('#npf-box-' + ingredients.revid).attr('data-categories', "0");
}
if(refTest === ' • فاقد منبع')
{
$('#npf-box-' + ingredients.revid).attr('data-refs', "0");
}
if (ingredients.notPatrolled) {
$('#npf-box-' + ingredients.revid).attr('data-patrolled', "0"); // add data attr for filtering
}
else{
$('#npf-box-' + ingredients.revid).attr('data-patrolled', "1"); // add data attr for filtering
}
// Show updated content
$('#cat-iw-container-' + ingredients.revid).fadeIn(1000);
}
);
///// EXTLINKS SPAN
$("#npf-extlinks-" + ingredients.revid).mouseenter(function() { // Outlinks mouse event handler
handleHover("#npf-extlinks-" + ingredients.revid, data.parse.externallinks);
});
});
}
// Handle external links box
function handleHover(spanid, extLinks) {
var listContent,
hasExtLinks = !!extLinks.length;
if (hasExtLinks) {
var links = extLinks.map(function(link) {
return '<a href="' + link + '" target="_blank">' + decodeURIComponent(link) + '</a>';
});
listContent = '<li>' + links.join('</li><li>') + '</li>';
} else {
listContent = '<span>این صفحه فاقد پیوند بیرونی است</span>';
}
var formattedText = '<ul>' + listContent + '</ul>';
var spanpos = $(spanid).offset();
var $box = $('<div>')
.html(formattedText)
.addClass('extlink-box')
.css({
top: spanpos.top + $(spanid).outerHeight() - 30 + "px",
left: spanpos.left + "px"
});
$("body").append($box);
$(spanid).add($box).mouseleave(function(event) {
if (event.target === $box[0]) {
$box.remove();
}
});
}
// Utility function to create container div for each row
function createRow(content) {
var $row = $('<div>').addClass('npf-row').append(content);
return $row;
}
function createBoxes(ingredients) {
var htmlID = 'npf-box-' + ingredients.revid; // Unique ID (e.g. npf-header-39298943) for each article box
var $box = $('<div>')
.attr('id', htmlID)
.addClass('npf-article-box');
if (ingredients.notPatrolled) { // Gray background for non-patrolled pages
$box.addClass('npf-notpatrolled')
.attr('title', 'مقالهٔ گشت نخورده');
$('#npf-box-' + ingredients.revid).attr('data-patrolled', "0"); // add data attr for filtering
}
var $header = $('<div>')
.attr('id', 'npf-header-' + ingredients.revid)
.addClass('npf-flex-row')
.append($('<span>')
.addClass('npf-row-content-right')
.css('display', 'inline-flex')
.append($('<span>')
.css('display', 'inline-flex')
.append(
$('<a>')
.attr({
'href': mw.util.getUrl(ingredients.title),
'title': ingredients.title
})
.addClass('npf-header-title')
.text(ingredients.title)
)
.append($('<span>')
.addClass('npf-ores-indicator')
.attr({
'id': 'npf-ores-' + ingredients.firstrevid
})
.css({
'display': 'none' // Adding the color yellow
})
.text('⚠')
)
)
.append(
$('<span>')
.addClass('npf-hist-link')
.append('(')
.append(
$('<a>')
.attr({
'href': mw.util.getUrl('Special:PageHistory/' + ingredients.title),
'title': 'تاریخچهٔ صفحهٔ ' + ingredients.title
})
.text('تاریخچه')
)
.append(')')
)
.append($('<span>')
.attr('title', 'حجم صفحه')
.css('margin-left', '5px')
.text(' · ' + ingredients.bytes + ' بایت')
)
.append($('<span>')
.attr({
'title': 'پیوندهای بیرونی استفاده شده در این مقاله',
'id': 'npf-extlinks-'+ ingredients.revid
})
.append(' · ')
.append($('<span>')
.css('border-bottom', '2px dotted Blue')
.text('پیوندهای بیرونی')
)
)
)
.append($('<span>')
.addClass('npf-row-content-left')
.append($('<a>')
.attr({
'href': mw.util.getUrl('Special:Permalink/' + ingredients.firstrevid),
'title': 'پیوند دائمی به نخستین نسخهٔ صفحه'
})
.text(ingredients.date)
)
);
var $details = $('<div>')
.attr('id', 'npf-details-' + ingredients.revid)
.addClass('npf-flex-row')
.append($('<span>')
.attr('title', 'ایجاد کنندهٔ صفحه')
.addClass('npf-row-content-right')
.append($('<span>')
.append('ایجاد شده توسط ')
.append($('<a>')
.addClass('npf-creator' + (ingredients.newUser ? ' new' : ''))
.attr('href', mw.util.getUrl('کاربر:' + ingredients.creator))
.text(ingredients.creator)
)
)
.append($(ingredients.userTools))
)
.append($('<span>')
.attr({
'id': 'cat-iw-container-' + ingredients.revid,
'title': 'لطفاً صبر کنید…'
})
.addClass('npf-row-content-left')
.text('در حال تجزیهٔ صفحه…')
);
var $comment = $('<div>')
.attr('id', 'npf-comment-' + ingredients.revid)
.addClass('npf-flex-row')
.append($('<span>')
.addClass('npf-row-content-right')
.attr('title', 'خلاصهٔ ویرایش در زمان ایجاد صفحه')
.append('خلاصهٔ ویرایش: ')
.append($('<span>')
.addClass('npf-italic')
.append($(ingredients.comment))
)
);
$box.append(createRow($header));
$box.append(createRow($details));
$box.append(createRow($comment));
// Append tag container only if we have some tags
if (ingredients.tags && ingredients.tags.length > 0) {
var $tagElements = $('<span>');
for (var t = 0; t < ingredients.tags.length; t++) {
$tagElements.append($(ingredients.tags[t]));
}
var $tags = $('<div>')
.attr('id', 'npf-tags-' + ingredients.revid)
.addClass('npf-tags-container')
.append($('<span>')
.attr('title', 'برچسبهای نصب شده بر نخستین ویرایش')
.append('برچسبها: ')
.append($tagElements)
);
$box.append(createRow($tags));
}
$('#npf-parent-container').append($box);
$('.mw-pager-navigation-bar').eq(1).insertAfter($box); // Move navigation bar to its initial location
}
function createFiltersBox() {
var buttons = {
patrolled: new OO.ui.ToggleButtonWidget({
icon: 'eye',
label: 'گشتخورده',
data: 'patrolled'
}),
unpatrolled: new OO.ui.ToggleButtonWidget({
icon: 'eyeClosed',
label: 'گشتنخورده',
data: 'notpatrolled'
}),
dmgLow: new OO.ui.ToggleButtonWidget({
icon: 'flag',
label: 'کم',
classes: ['npf-button-green'],
data: 'ores-low'
}),
dmgAverage: new OO.ui.ToggleButtonWidget({
icon: 'flag',
label: 'متوسط',
classes: ['npf-button-yellow'],
data: 'ores-average'
}),
dmgHigh: new OO.ui.ToggleButtonWidget({
icon: 'flag',
label: 'زیاد',
classes: ['npf-button-red'],
data: 'ores-high'
}),
noCat: new OO.ui.ToggleButtonWidget({
icon: 'listBullet',
label: 'فاقد رده',
data: 'nocat'
}),
noIW: new OO.ui.ToggleButtonWidget({
icon: 'language',
label: 'فاقد میانویکی',
data: 'noIW'
}),
noRefs: new OO.ui.ToggleButtonWidget({
icon: 'references',
label: 'فاقد منبع',
data: 'norefs'
}),
};
var allboxes = [];
$('[id^="npf-box-"]').each(function() {
allboxes.push($(this).attr('id').match(/\d+$/)[0]);
});
Object.keys(buttons).forEach(function(key) { // Get all revids for filtering
buttons[key].setValue(true);
buttons[key].on('change', function(state) {
applyFilter(state, buttons, allboxes);
});
});
var firstButtonGroup = new OO.ui.ButtonGroupWidget({
items: [
buttons.patrolled,
buttons.unpatrolled
]
});
var secondButtonGroup = new OO.ui.ButtonGroupWidget({
items: [
buttons.dmgLow,
buttons.dmgAverage,
buttons.dmgHigh
]
});
var thirdButtonGroup = new OO.ui.ButtonGroupWidget({
items: [
buttons.noCat,
buttons.noIW,
buttons.noRefs
]
});
var helpText = new OO.ui.MessageWidget({
type: 'notice',
label: 'هر کدام از گزینههای زیر را که غیرفعال کنید، مقالههای دارای معیار آن گزینه از فهرست پنهان خواهند شد.'
});
var $filtersBox = $('<div>')
.attr('id', 'npf-filters-box')
.addClass('npf-filters-box')
.append($('<div>')
.addClass('npf-flex-row npf-filters-title')
.append($('<span>')
.text('گزینههای پالایش فهرست')
)
)
.append($('<div>')
.addClass('npf-row')
.css('margin-bottom', '12px')
.append(helpText.$element)
)
.append($('<div>')
.attr('align', 'center')
.append(
firstButtonGroup.$element,
secondButtonGroup.$element,
thirdButtonGroup.$element
)
);
$('.mw-pager-navigation-bar:first').after($filtersBox);
}
function applyFilter(state, buttons, allboxes) {
//////// Get Active Filters : START
var activefilters = [];
Object.keys(buttons).forEach(function(key) {
if (!buttons[key].getValue()) {
switch(buttons[key].getData()) {
case 'patrolled':
activefilters.push('patrolled');
break;
case 'notpatrolled':
activefilters.push('notpatrolled');
break;
case 'ores-low':
activefilters.push('ores-low');
break;
case 'ores-average':
activefilters.push('ores-average');
break;
case 'ores-high':
activefilters.push('ores-high');
break;
case 'nocat':
activefilters.push('nocat');
break;
case 'noIW':
activefilters.push('noIW');
break;
case 'norefs':
activefilters.push('norefs');
break;
default:
break;
}
}
});
//////// Get Active Filters : END
//////// Calculate filtered boxes : START
var filteredBoxes = [];
var notfilteredboxes = [];
if(activefilters.includes('patrolled'))
{
$('[data-patrolled]').each(function() {
if($(this).attr('data-patrolled') == 1)
{
filteredBoxes.push($(this).attr('id').match(/\d+$/)[0]);
}
});
}
if(activefilters.includes('notpatrolled'))
{
$('[data-patrolled]').each(function() {
if($(this).attr('data-patrolled') == 0)
{
filteredBoxes.push($(this).attr('id').match(/\d+$/)[0]);
}
});
}
if(activefilters.includes('ores-low'))
{
$('[data-ores]').each(function() {
if($(this).attr('data-ores') == 1)
{
filteredBoxes.push($(this).attr('id').match(/\d+$/)[0]);
}
});
}
if(activefilters.includes('ores-average'))
{
$('[data-ores]').each(function() {
if($(this).attr('data-ores') == 2)
{
filteredBoxes.push($(this).attr('id').match(/\d+$/)[0]);
}
});
}
if(activefilters.includes('ores-high'))
{
$('[data-ores]').each(function() {
if($(this).attr('data-ores') == 3)
{
filteredBoxes.push($(this).attr('id').match(/\d+$/)[0]);
}
});
}
if(activefilters.includes('nocat'))
{
$('[data-categories]').each(function() {
if($(this).attr('data-categories') == 0)
{
filteredBoxes.push($(this).attr('id').match(/\d+$/)[0]);
}
});
}
if(activefilters.includes('noIW'))
{
$('[data-langlinks]').each(function() {
if($(this).attr('data-langlinks') == 0)
{
filteredBoxes.push($(this).attr('id').match(/\d+$/)[0]);
}
});
}
if(activefilters.includes('norefs'))
{
$('[data-refs]').each(function() {
if($(this).attr('data-refs') == 0)
{
filteredBoxes.push($(this).attr('id').match(/\d+$/)[0]);
}
});
}
var filteredBoxesUnique = [];
$.each(filteredBoxes, function(i, el){
if($.inArray(el, filteredBoxesUnique) === -1) filteredBoxesUnique.push(el);
});
notfilteredboxes = allboxes.filter(item => !filteredBoxesUnique.includes(item));
//////// Calculate filtered boxes (filteredBoxesUnique) : END
for (var i = 0 ; i < filteredBoxesUnique.length ; i++)
{
$('#npf-box-' + filteredBoxesUnique[i]).slideUp('slow', 'swing');
}
for (var i = 0 ; i < notfilteredboxes.length ; i++)
{
$('#npf-box-' + notfilteredboxes[i]).slideDown('slow', 'swing');
}
}
var listItems = $('#mw-content-text > section.mw-pager-body > ul > li'),
boxIngredients = [], // Will be populated by information from list items without any API calls
i;
for (i = 0; i < listItems.length; i++) {
var hasTags = $(listItems[i])[0].children[9]; // ...children[8] is always for edit tags
boxIngredients[i] = {
notPatrolled: !!$(listItems[i]).hasClass('not-patrolled'),
title: $(listItems[i])[0].children[1].title,
url: $(listItems[i])[0].children[1].href,
date: $(listItems[i])[0].children[1].innerText,
revid: $($(listItems[i])[0]).attr('data-mw-revid'), // Latest revision's ID is available as "data-mw-revid" attribute for each list item
firstrevid: $(listItems[i])[0].children[1].href.match(/\oldid\=(\d*)/)[1], // First revision's ID
bytes: ($(listItems[i])[0].children[5].innerText).replace(/\[(.*) بایت\]/, '$1'),
creator: $(listItems[i])[0].children[6].innerText,
userTools: $(listItems[i])[0].children[7],
comment: ($(listItems[i])[0].children[8])
};
if (hasTags) { // We have some tags
boxIngredients[i].tags = [];
for (var ei = 0; ei < $(listItems[i])[0].children[9].children.length; ei++) {
var $element = $($(listItems[i])[0].children[9].children[ei]);
if ($element.hasClass('mw-tag-marker')) { // Prevent pushing "برچسبها" to array
// Store tags as jquery object so we can add
// them to the box with without modifications
boxIngredients[i].tags.push($element);
}
}
}
if ($($(listItems[i])[0].children[6]).hasClass('new')) {
boxIngredients[i].newUser = true;
}
}
$('#mw-content-text section.mw-pager-body > ul').remove();
$('#mw-content-text section.mw-pager-body').append('<div id="npf-parent-container"></div>'); // Append main parent container
for (i = 0; i < boxIngredients.length; i++) {
createBoxes(boxIngredients[i]); // Create boxes
parsePage(boxIngredients[i]); // Update categories and langlinks after we have the api response
}
createFiltersBox();
});