Bureaucrats, Moderators (CommentStreams), Interface administrators, Push subscription managers, Suppressors, Administrators
13,446
edits
(add JavaScript-Based Time Zone Detection) |
(help with saint of the day parsing) |
||
| Line 1: | Line 1: | ||
/* Any JavaScript here will be loaded for all users on every page load. */ | /* Any JavaScript here will be loaded for all users on every page load. */ | ||
// Utility | // Utility functions for cookies | ||
function setCookie(name, value, days) { | function setCookie(name, value, days) { | ||
const expires = new Date(Date.now() + days * 864e5).toUTCString(); | const expires = new Date(Date.now() + days * 864e5).toUTCString(); | ||
| Line 11: | Line 11: | ||
mw.hook('wikipage.content').add(function($content) { | mw.hook('wikipage.content').add(function($content) { | ||
if (mw.user.isAnon()) { | if (mw.user.isAnon()) { | ||
// Detect user's time zone | // Detect user's time zone | ||
let userTimeZone; | let userTimeZone; | ||
try { | try { | ||
| Line 22: | Line 21: | ||
} | } | ||
// Cache time zone | // Cache time zone | ||
try { | try { | ||
localStorage.setItem('wiki_user_timezone', userTimeZone); | localStorage.setItem('wiki_user_timezone', userTimeZone); | ||
| Line 30: | Line 29: | ||
} | } | ||
// | // Timestamp selectors | ||
const timestampSelectors = [ | const timestampSelectors = [ | ||
'.mw-changeslist-date', // Recent changes | '.mw-changeslist-date', // Recent changes | ||
| Line 39: | Line 38: | ||
'span.history-user-info span', // User signatures | 'span.history-user-info span', // User signatures | ||
'.smw-timestamp', // Semantic MediaWiki | '.smw-timestamp', // Semantic MediaWiki | ||
'.dpl-timestamp' // DynamicPageList | '.dpl-timestamp', // DynamicPageList | ||
'.custom-time' // Custom {{#time:F j}} or {{#time:F d}} | |||
].join(','); | ].join(','); | ||
const timestamps = $content.find(timestampSelectors); | const timestamps = $content.find(timestampSelectors); | ||
const userLang = mw.config.get('wgUserLanguage') || 'en-US'; | const userLang = mw.config.get('wgUserLanguage') || 'en-US'; | ||
const updateTimestamps = debounce(function() { | const updateTimestamps = debounce(function() { | ||
timestamps.each(function() { | timestamps.each(function() { | ||
const $element = $(this); | const $element = $(this); | ||
let utcTime = $element.attr('data-mw-timestamp') || $element.text().trim(); | let utcTime = $element.attr('data-mw-timestamp') || $element.text().trim(); | ||
let isLeadingZeroFormat = false; | |||
try { | try { | ||
// | // Detect {{#time:F j}} (e.g., "September 7") or {{#time:F d}} (e.g., "September 07") | ||
if (/^[A-Za-z]+ \d{1,2}$/.test(utcTime)) { | |||
isLeadingZeroFormat = utcTime.match(/^[A-Za-z]+ 0\d$/); // Check for leading zero (e.g., "September 07") | |||
utcTime = `${utcTime}, ${new Date().getFullYear()} 00:00:00 UTC`; | |||
} | |||
let date; | let date; | ||
try { | try { | ||
| Line 64: | Line 67: | ||
} | } | ||
const options = { | const options = { | ||
timeZone: userTimeZone, | timeZone: userTimeZone, | ||
year: 'numeric', | year: 'numeric', | ||
month: ' | month: 'long', | ||
day: 'numeric', | day: isLeadingZeroFormat ? '2-digit' : 'numeric', // Use leading zeros if input has them | ||
hour: 'numeric', | hour: 'numeric', | ||
minute: 'numeric', | minute: 'numeric', | ||
second: 'numeric', | second: 'numeric', | ||
hour12: userLang === 'en-US' | hour12: userLang === 'en-US' | ||
}; | }; | ||
const formattedTime = date.toLocaleString(userLang, | const formattedTime = date.toLocaleString(userLang, { | ||
timeZone: userTimeZone, | |||
month: 'long', | |||
day: isLeadingZeroFormat ? '2-digit' : 'numeric' | |||
}); | |||
const timeZoneAbbr = new Intl.DateTimeFormat(userLang, { | const timeZoneAbbr = new Intl.DateTimeFormat(userLang, { | ||
timeZone: userTimeZone, | timeZone: userTimeZone, | ||
| Line 82: | Line 88: | ||
|| userTimeZone.split('/').pop().replace('_', ' ') || userTimeZone; | || userTimeZone.split('/').pop().replace('_', ' ') || userTimeZone; | ||
$element.text(`${formattedTime} (${timeZoneAbbr})`); | $element.text(`${formattedTime} (${timeZoneAbbr})`); | ||
$element.attr('title', `Original UTC: ${utcTime}`); | $element.attr('title', `Original UTC: ${utcTime}`); | ||
| Line 95: | Line 100: | ||
}); | }); | ||
// Non-intrusive prompt | // Non-intrusive prompt | ||
let prompted = false; | let prompted = false; | ||
const currentZone = Intl.DateTimeFormat().resolvedOptions().timeZone; | const currentZone = Intl.DateTimeFormat().resolvedOptions().timeZone; | ||
| Line 133: | Line 138: | ||
} | } | ||
function debounce(func, wait) { | function debounce(func, wait) { | ||
let timeout; | let timeout; | ||