MediaWiki:Gadget-ChangestoPatrol.js: Difference between revisions
Page last edited 3 months ago by Xeverything11
JS for RC |
clarification, noted JS code is AI-generated |
||
Line 1: | Line 1: | ||
// MediaWiki:Common.js | // Generated by ChatGPT o4-mini | ||
// Prompts below: | |||
// Write me JS code to display recent changes for a wiki using MediaWiki Action API | |||
// Make sure it is ES6-compatible so it can work on MediaWiki:Common.js on a MediaWiki wiki. | |||
/* | |||
[[User:Xeverything11|Xeverything11]] ([[User talk:Xeverything11|talk]]) | |||
<templatestyles src="RecentChanges/styles.css" /> | |||
<div class="mw-parser-output"> | |||
<div class="rc-container"> | |||
<div class="rc-header"> | |||
<div class="rc-unpatrolled">[[Special:RecentChanges|<span id="RCUnpatrolled">16</span> {{material icon|1=<span id="RCUnpatrolledIcon">sunny</span>|size=inherit}}]]</div> | |||
Changes to patrol</div> | |||
<div class="rc-main" id="RCMain"> | |||
JavaScript is required to view the recent changes. | |||
</div> | |||
</div> | |||
</div> | |||
[[User:Xeverything11|Xeverything11]] ([[User talk:Xeverything11|talk]]) | |||
1. Remove all children from #RCMain | |||
2. Prepend three most recent changes into #RCMain. | |||
3. Wait 3 seconds. | |||
4. Prepend the next recent change (4th). | |||
5. Repeat steps 3-4. (5th, 6th, 7th change etc.) | |||
Format: | |||
<username> <action> <page> | |||
<time ago> ago | |||
Example | |||
Xeverything11 edited Make Vegan Gingerbread | |||
13 hours ago | |||
*/ | |||
// 1ms after each RC prepends, add .rc-active CSS class to that (to allow transitions). | |||
/* | |||
edit -> edited | |||
new -> created | |||
log seems vague, it can be "uploaded", "moved", "blocked", "protected" etc. | |||
*/ | |||
mw.loader.using('mediawiki.api').then(() => { | mw.loader.using('mediawiki.api').then(() => { | ||
Line 5: | Line 45: | ||
const RC_CONTAINER = document.getElementById('RCMain'); | const RC_CONTAINER = document.getElementById('RCMain'); | ||
// | // Convert timestamp into "X minutes ago" | ||
const timeAgo = timestamp => { | const timeAgo = timestamp => { | ||
const seconds = Math.floor((Date.now() - new Date(timestamp)) / 1000); | const seconds = Math.floor((Date.now() - new Date(timestamp)) / 1000); | ||
Line 23: | Line 63: | ||
}; | }; | ||
// | // Map MediaWiki RC types and logtypes to readable verbs | ||
const prependChange = | const getActionVerb = change => { | ||
const type = change.type; | |||
if (type === 'edit') return 'edited'; | |||
if (type === 'new') return 'created'; | |||
if (type === 'log') { | |||
const map = { | |||
move: 'moved', | |||
upload: 'uploaded', | |||
block: 'blocked', | |||
protect: 'protected', | |||
delete: 'deleted', | |||
rights: 'changed rights', | |||
patrol: 'patrolled', | |||
import: 'imported', | |||
tag: 'tagged', | |||
}; | |||
return map[change.logtype] || 'performed log action'; | |||
} | |||
return type; // fallback (e.g. external, unknown future types) | |||
}; | |||
// Prepend entry with .rc-active after 1ms | |||
const prependChange = change => { | |||
const verb = getActionVerb(change); | |||
const entry = document.createElement('div'); | const entry = document.createElement('div'); | ||
entry.className = 'rc-entry'; | entry.className = 'rc-entry'; | ||
entry.innerHTML = ` | entry.innerHTML = ` | ||
<div class="rc-line1"> | <div class="rc-line1"> | ||
<strong>${mw.html.escape( | <strong>${mw.html.escape(change.user)}</strong> | ||
${ | ${verb} | ||
<a href="${mw.config.get('wgServer') + mw.config.get('wgScriptPath')}/index.php?title=${encodeURIComponent( | <a href="${mw.config.get('wgServer') + mw.config.get('wgScriptPath')}/index.php?title=${encodeURIComponent(change.title)}"> | ||
${mw.html.escape( | ${mw.html.escape(change.title)} | ||
</a> | </a> | ||
</div> | </div> | ||
<div class="rc-line2"> | <div class="rc-line2"> | ||
${timeAgo( | ${timeAgo(change.timestamp)} ago | ||
</div> | </div> | ||
`; | `; | ||
RC_CONTAINER.insertBefore(entry, RC_CONTAINER.firstChild); | RC_CONTAINER.insertBefore(entry, RC_CONTAINER.firstChild); | ||
setTimeout(() => { | setTimeout(() => { | ||
entry.classList.add('rc-active'); | entry.classList.add('rc-active'); | ||
Line 46: | Line 108: | ||
}; | }; | ||
// | // Load recent changes | ||
api.get({ | api.get({ | ||
action: | action: 'query', | ||
list: | list: 'recentchanges', | ||
rcprop: | rcprop: 'title|ids|sizes|comment|user|timestamp|flags|loginfo', | ||
rclimit: 50, | rclimit: 50, | ||
rcshow: | rcshow: '!bot', | ||
format: | format: 'json' | ||
}).then(data => { | }).then(data => { | ||
const changes = data.query.recentchanges; | const changes = data.query.recentchanges; | ||
// | |||
// Clear placeholder | |||
RC_CONTAINER.replaceChildren(); | RC_CONTAINER.replaceChildren(); | ||
// | // Add first 3 immediately | ||
changes.slice(0, 3).forEach(prependChange); | changes.slice(0, 3).forEach(prependChange); | ||
// | // Add rest with delay | ||
let idx = 3; | let idx = 3; | ||
const timer = setInterval(() => { | const timer = setInterval(() => { |
Revision as of 17:32, 23 June 2025
// Generated by ChatGPT o4-mini
// Prompts below:
// Write me JS code to display recent changes for a wiki using MediaWiki Action API
// Make sure it is ES6-compatible so it can work on MediaWiki:Common.js on a MediaWiki wiki.
/*
[[User:Xeverything11|Xeverything11]] ([[User talk:Xeverything11|talk]])
<templatestyles src="RecentChanges/styles.css" />
<div class="mw-parser-output">
<div class="rc-container">
<div class="rc-header">
<div class="rc-unpatrolled">[[Special:RecentChanges|<span id="RCUnpatrolled">16</span> {{material icon|1=<span id="RCUnpatrolledIcon">sunny</span>|size=inherit}}]]</div>
Changes to patrol</div>
<div class="rc-main" id="RCMain">
JavaScript is required to view the recent changes.
</div>
</div>
</div>
[[User:Xeverything11|Xeverything11]] ([[User talk:Xeverything11|talk]])
1. Remove all children from #RCMain
2. Prepend three most recent changes into #RCMain.
3. Wait 3 seconds.
4. Prepend the next recent change (4th).
5. Repeat steps 3-4. (5th, 6th, 7th change etc.)
Format:
<username> <action> <page>
<time ago> ago
Example
Xeverything11 edited Make Vegan Gingerbread
13 hours ago
*/
// 1ms after each RC prepends, add .rc-active CSS class to that (to allow transitions).
/*
edit -> edited
new -> created
log seems vague, it can be "uploaded", "moved", "blocked", "protected" etc.
*/
mw.loader.using('mediawiki.api').then(() => {
const api = new mw.Api();
const RC_CONTAINER = document.getElementById('RCMain');
// Convert timestamp into "X minutes ago"
const timeAgo = timestamp => {
const seconds = Math.floor((Date.now() - new Date(timestamp)) / 1000);
const intervals = [
{ label: 'day', secs: 86400 },
{ label: 'hour', secs: 3600 },
{ label: 'minute', secs: 60 },
{ label: 'second', secs: 1 }
];
for (const { label, secs } of intervals) {
const count = Math.floor(seconds / secs);
if (count > 0) {
return `${count} ${label}${count > 1 ? 's' : ''}`;
}
}
return 'just now';
};
// Map MediaWiki RC types and logtypes to readable verbs
const getActionVerb = change => {
const type = change.type;
if (type === 'edit') return 'edited';
if (type === 'new') return 'created';
if (type === 'log') {
const map = {
move: 'moved',
upload: 'uploaded',
block: 'blocked',
protect: 'protected',
delete: 'deleted',
rights: 'changed rights',
patrol: 'patrolled',
import: 'imported',
tag: 'tagged',
};
return map[change.logtype] || 'performed log action';
}
return type; // fallback (e.g. external, unknown future types)
};
// Prepend entry with .rc-active after 1ms
const prependChange = change => {
const verb = getActionVerb(change);
const entry = document.createElement('div');
entry.className = 'rc-entry';
entry.innerHTML = `
<div class="rc-line1">
<strong>${mw.html.escape(change.user)}</strong>
${verb}
<a href="${mw.config.get('wgServer') + mw.config.get('wgScriptPath')}/index.php?title=${encodeURIComponent(change.title)}">
${mw.html.escape(change.title)}
</a>
</div>
<div class="rc-line2">
${timeAgo(change.timestamp)} ago
</div>
`;
RC_CONTAINER.insertBefore(entry, RC_CONTAINER.firstChild);
setTimeout(() => {
entry.classList.add('rc-active');
}, 1);
};
// Load recent changes
api.get({
action: 'query',
list: 'recentchanges',
rcprop: 'title|ids|sizes|comment|user|timestamp|flags|loginfo',
rclimit: 50,
rcshow: '!bot',
format: 'json'
}).then(data => {
const changes = data.query.recentchanges;
// Clear placeholder
RC_CONTAINER.replaceChildren();
// Add first 3 immediately
changes.slice(0, 3).forEach(prependChange);
// Add rest with delay
let idx = 3;
const timer = setInterval(() => {
if (idx >= changes.length) {
clearInterval(timer);
} else {
prependChange(changes[idx++]);
}
}, 3000);
}).catch(err => {
console.error('Failed to load recent changes:', err);
RC_CONTAINER.textContent = 'Error loading recent changes.';
});
});