User:Ladsgroup/dashboard.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. |
Documentation for this user script can be added at User:Ladsgroup/dashboard. |
// License: GPL-v3 or later
// Keep in sync with https://gitlab.wikimedia.org/ladsgroup/dashboard-gadget/-/blob/main/main.js
function dashboardGadget() {
function msg( key ){
const i18n = {
'en': {
'dashboard': 'Dashboard',
'dashboard-message': 'Go to the dashboard',
'loading': 'Loading...',
'diff': 'Diff',
'refresh': 'Refresh',
'configuration': 'Configuration',
'pending-since': 'Pending since',
'default-config': 'User:Ladsgroup/defaultDashboardConfig.json'
},
'fa': {
'dashboard': 'پیشخوان',
'dashboard-message': 'رفتن به صفحهٔ پیشخوان عمومی',
'loading': 'در حال بارگذاری...',
'diff': 'تفاوت',
'refresh': 'بروزرسانی',
'configuration': 'تنظیمات',
'pending-since': 'در حال انتظار از',
'default-config': 'مدیاویکی:Gadget-dashboard/defaultConfig.json'
},
'de': {
'dashboard': 'Dashboard',
'dashboard-message': 'Go to the dashboard',
'loading': 'Laden...',
'diff': 'Unterschied',
'refresh': 'Neuladen',
'configuration': 'Einstellungen',
'pending-since': 'Ungesichtet seit',
'default-config': 'User:Ladsgroup/defaultConfig.json'
}
};
return i18n[ mw.config.get( 'wgUserLanguage' ).split('-')[0] ][ key ] || i18n.en[ key ];
}
// inject the link
if ($('.vector-user-links').length) {
// new vector
let dashboardLinkDiv = $('<div></div>');
dashboardLinkDiv.css('margin', '5px');
let link = $('<a></a>');
link.attr('href', '/wiki/Special:BlankPage/Dashboard');
link.text(msg('dashboard'))
dashboardLinkDiv.append(link);
dashboardLinkDiv.append(' - ');
$('.vector-user-links').prepend(dashboardLinkDiv);
} else {
// old vector
mw.util.addPortletLink('p-personal', '/wiki/Special:BlankPage/Dashboard', msg('dashboard'), 'p-dashboard', msg('dashboard-message'), null, '#pt-userpage');
}
if (
mw.config.get( 'wgCanonicalNamespace' ) != 'Special' ||
mw.config.get( 'wgCanonicalSpecialPageName' ) != 'Blankpage' ||
mw.config.get( 'wgPageName' ).search( '/Dashboard' ) == -1
) {
return;
}
document.documentElement.classList.remove('vector-feature-limited-width-clientpref-1');
document.documentElement.classList.add('vector-feature-limited-width-clientpref-0');
document.documentElement.classList.remove('vector-feature-page-tools-pinned-enabled');
document.documentElement.classList.add('vector-feature-page-tools-pinned-disabled');
$('.vector-page-toolbar').remove();
window.dispatchEvent( new Event( 'resize' ) );
$('.mw-first-heading').text(msg('dashboard'));
document.title = msg('dashboard');
$('.mw-body-content').text(msg('loading'));
async function loadConfig( title ) {
let response = await fetch("/wiki/" + encodeURIComponent(title) + '?action=raw');
return response.text();
}
async function contentForPageType( box ) {
let response = await fetch("/enwiki/api/rest_v1/page/html/" + encodeURIComponent(box.pageTitle));
return response.text();
}
async function contentForRC( box ) {
let response = await fetch(box.url);
let data = await response.json();
data = data.query.recentchanges;
let content = $('<ul></ul>');
for ( i in data ) {
let diff = $('<a></a>');
diff.attr('href', '/wiki/Special:Diff/' + Number(data[i].revid));
diff.text(msg('diff'));
let liObj = $('<li></li>');
liObj.append('(');
liObj.append(diff);
liObj.append(') - ');
liObj.append(getPageLink(data[i].title));
liObj.append(' ');
liObj.append(getUser(data[i].user));
liObj.append( ' (' + data[i].parsedcomment + ')' );
content.append(liObj);
}
return content;
}
async function contentForWatchlist( box ) {
let response = await fetch(box.url);
let data = await response.json();
data = data.query.watchlist;
let content = $('<ul></ul>');
for ( i in data ) {
let diff = $('<a></a>');
diff.attr('href', '/wiki/Special:Diff/' + Number(data[i].revid));
diff.text(msg('diff'));
let liObj = $('<li></li>');
liObj.append('(');
liObj.append(diff);
liObj.append(') - ');
liObj.append(getPageLink(data[i].title));
liObj.append(' ');
liObj.append(getUser(data[i].user));
liObj.append( ' (' + data[i].parsedcomment + ')' );
content.append(liObj);
}
return content;
}
async function contentForPending( box ) {
let response = await fetch(box.url);
let data = await response.json();
data = data.query.oldreviewedpages;
if ( !data ) {
return 'Nothing to review!';
}
let content = $('<ul></ul>');
for ( i in data ) {
let diff = $('<a></a>');
diff.attr('href', '/wiki/Special:Diff/' + Number(data[i].revid));
diff.text(msg('diff'));
let liObj = $('<li></li>');
liObj.append('(');
liObj.append(diff);
liObj.append(') - ');
liObj.append(getPageLink(data[i].title));
liObj.append( ' (' + msg('pending-since') + ': ' + data[i].pending_since + ')' );
content.append(liObj);
}
return content;
}
async function contentForCategory( box ) {
let api = new mw.Api();
if (box.norandom) {
limit = 10;
} else {
limit = 100;
}
let data = await api.get( {
action: 'query',
list: 'categorymembers',
cmprop: 'title',
cmlimit: limit,
cmtitle: box.categoryTitle
} );
data = getMultipleRandom(data.query.categorymembers, 10);
let content = $('<ul></ul>');
for ( i in data ) {
let liObj = $('<li></li>');
liObj.append(getPageLink(data[i].title));
content.append(liObj);
}
return content;
}
async function contentForLinks( box ) {
let content = $('<ul></ul>');
for ( i in box.links ) {
let link = box.links[i];
if ( link.page ) {
let liObj = $('<li></li>');
liObj.append(getPageLink(link.page));
content.append(liObj);
} else if ( link.url ) {
let link = $('<a>');
link.attr('href', encodeURIComponent(link.url));
link.text(link.text);
let liObj = $('<li></li>');
liObj.append(link);
content.append(liObj);
}
}
return content;
}
async function contnetForStats() {
let api = new mw.Api();
let data = await api.get( {
action: 'query',
meta: 'siteinfo',
siprop: 'statistics',
} );
let content = '<ul>';
content += '<li>تعداد مقالات: ' + mw.language.convertNumber(data.query.statistics.articles) + '</li>';
content += '<li>تعداد صفحات: ' + mw.language.convertNumber(data.query.statistics.pages) + '</li>';
content += '<li>تعداد ویرایشها: ' + mw.language.convertNumber(data.query.statistics.edits) + '</li>';
content += '<li>تعداد تصاویر: ' + mw.language.convertNumber(data.query.statistics.images) + '</li>';
content += '<li>تعداد کاربران فعال: ' + mw.language.convertNumber(data.query.statistics.activeusers) + '</li>';
return content + '</ul>';
}
async function contnetForCx() {
let api = new mw.Api();
let data = await api.get( {
action: 'query',
assert: 'user',
list: 'contenttranslationsuggestions',
from: 'en',
to: 'fa',
limit: 10,
seed: Math.floor(Math.random() * 100)
} );
data = data.query.contenttranslationsuggestions.lists;
let content = $('<ul></ul>');
for ( i in data ) {
for (j in data[i].suggestions) {
let link = $('<a>');
link.attr('href', 'https://en.wikipedia.org/wiki/' + encodeURIComponent(data[i].suggestions[j].title));
link.text(data[i].suggestions[j].title);
let liObj = $('<li></li>');
liObj.append(link);
content.append(liObj);
}
}
let divObj = $('<div direction="ltr"></div>');
divObj.append(content);
return divObj;
}
const handlers = {
'page': contentForPageType,
'rc': contentForRC,
'watchlist': contentForWatchlist,
'category': contentForCategory,
'pending': contentForPending,
'links': contentForLinks,
'stats': contnetForStats,
'cx': contnetForCx,
};
function getUser(username) {
let link = $('<a>');
link.attr('href', '/wiki/User:' + encodeURIComponent(username));
link.text(username);
return link;
}
function getPageLink( title ) {
let link = $('<a>');
link.attr('href', '/wiki/' + encodeURIComponent(title));
link.text(title);
return link;
}
function getMultipleRandom(arr, num) {
const shuffled = [...arr].sort(() => 0.5 - Math.random());
return shuffled.slice(0, num);
}
function loadBoxes() {
$('.mw-body-content').text(msg('loading'));
let tabs = $('<div class="cdx-tabs"></div>');
let tabsHeader = $('<div class="cdx-tabs__header"><div class="cdx-tabs__list"></div></div>');
let tabsContent = $( '<div class="cdx-tabs__content"></div>');
for ( let tabIndex in window.dashboardConfig.tabs ) {
let tabConfig = window.dashboardConfig.tabs[tabIndex];
let headerElement = $('<span class="cdx-tabs__list__item"></span>');
headerElement.text( tabConfig.title );
headerElement.on( 'click', () => {
window.dashboardActiveTab = tabIndex;
loadBoxes();
});
if ( tabIndex == ( window.dashboardActiveTab || 0 ) ) {
headerElement.attr('aria-selected', true);
}
tabsHeader.append(headerElement);
let tabContent = $( '<div class="cdx-tab"></div>');
tabContent.attr( 'id', 'tab-content-' + tabIndex );
tabContent.css('display', 'flex');
tabContent.css('flex-wrap', 'wrap');
tabContent.css('align-items', 'flex-start');
for (let i in tabConfig.boxes) {
i = Number(i);
let box = tabConfig.boxes[i];
let element = $('<span class="cdx-card__text"></span>');
let titleElement = $('<span class="cdx-card__text__title"></span>');
titleElement.text(box.title);
element.append(titleElement);
let contentElement = $('<span></span>');
contentElement.attr('class', 'cdx-card__text__supporting-text');
contentElement.attr('id', 'dashboard-box-' + i);
contentElement.append('<span class="cdx-css-icon--clock"></span>');
contentElement.append(msg('loading'));
contentElement.css('width', box.width || '300px' );
contentElement.css('height', box.height || '300px' );
contentElement.css('overflow', 'scroll' );
element.append(contentElement);
let wrapper = $( '<span class="cdx-card"></span>' );
wrapper.append(element);
wrapper.css('padding', '15px' );
wrapper.css('margin', '15px' );
const activeTab = window.dashboardActiveTab || 0;
if ( tabIndex == activeTab ) {
wrapper.css('display', 'inline-flex');
tabsContent.append(wrapper);
if ( handlers[box.type] ) {
handlerPromise = handlers[box.type](box);
} else {
handlerPromise = new Promise(() => { return 'No handler has been found' } );
}
handlerPromise.then( ( content ) => { $( '#dashboard-box-' + i).html( content )});
} else {
wrapper.css('display', 'none');
}
}
}
tabs.append(tabsHeader);
let direction = 'left';
if (document.dir == 'rtl') {
direction = 'right';
}
let refreshButton = $('<button class="cdx-button cdx-button--action-progressive"></button>');
refreshButton.append('<span class="cdx-button__icon cdx-css-icon--reload"></span>');
refreshButton.text(msg('refresh'));
refreshButton.css( 'align-self', 'flex-end' );
refreshButton.css( 'margin-bottom', '5px' );
refreshButton.css( 'margin-' + direction, '5px' );
refreshButton.on('click', loadBoxes );
let configButton = $('<button class="cdx-button cdx-button--action-progressive"></button>');
configButton.append('<span class="cdx-button__icon cdx-css-icon--reload"></span>');
configButton.text(msg('configuration'));
let configLink = $('<a></a>');
configLink.attr('href', '/wiki/ ' + encodeURIComponent( window.dashboardConfigLocation ));
configLink.attr('target', '_blank');
configLink.append(configButton);
configLink.css( 'margin-bottom', '5px' );
configLink.css( 'margin-' + direction, 'auto');
tabsHeader.append( configLink );
tabsHeader.append( refreshButton );
tabs.append(tabsContent);
$('.mw-body-content').html(tabs);
}
let configPromise = null;
if ( mw.util.getParamValue( 'dashboardConfig' ) ) {
configPromise = loadConfig( mw.util.getParamValue( 'dashboardConfig' ) );
window.dashboardConfigLocation = mw.util.getParamValue( 'dashboardConfig' );
} else {
configPromise = loadConfig('User:' + mw.config.get('wgUserName') + '/dashboardConfig.json' )
.then( function (res) {
try {
JSON.parse(res);
window.dashboardConfigLocation = 'User:' + mw.config.get('wgUserName') + '/dashboardConfig.json';
return res;
} catch (erorr) {
window.dashboardConfigLocation = msg('default-config');
return loadConfig(msg('default-config'));
}
} );
}
configPromise.then( function (res) {
let config = JSON.parse(res);
window.dashboardConfig = config;
mw.loader.using('codex-styles').then( loadBoxes() );
});
};
(function ($, mw) {
dashboardGadget();
}(jQuery, mediaWiki));