User:Mxn/CommentsInLocalTime/sandbox.js: Difference between revisions

Content deleted Content added
No edit summary
Overshot a bit
 
(23 intermediate revisions by the same user not shown)
Line 23:
/**
* Formats to display inline for each timestamp, keyed by a few common.
* cases.
*
* If a property ofis thisan object, isits set`type` toand a`options` string,may the timestamp isbe:
* formatted according to the documentation at
* <http://momentjs.com/docs/#/displaying/format/>.
*
* `type` | `options`
* If a property of this object is set to a function, it is called to
* -----------|----------
* retrieve the formatted timestamp string. See
* `relative` | `Intl.RelativeTimeFormat` options
* <http://momentjs.com/docs/#/displaying/> for the various things you can
* `absolute` | `Intl.AbsoluteTimeFormat` options
* do with the passed-in moment object.
* `iso8601` | —
*
* If a property is a function, it is called to retrieve the formatted
* timestamp string. The function must accept one argument, a `Date` object.
*
* If no `options` is specified, the timestamp adheres to the user’s date
* format and timezone preferences.
*/
formatsoutputFormats: {
/**
* Relative dates are helpful if the user doesn’t remember today’s date.
* Within a day, show a relative time that’s easy to relate to.
* The tooltip provides a more specific timestamp to distinguish
* comments in rapid succession.
*
* See <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#options>.
*/
relative: {
day: function (then) { return then.fromNow(); },
numeric: "auto",
},
/**
* Absolute dates are helpful for more distant dates, so that the user
* Within a week, show a relative date and specific time, still helpful
* if the user doesn’t rememberhave today’sto date.do Don’tmath showin justtheir a relativehead.
*
* time, because a discussion may need more context than “Last Friday”
* See <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#date-time_component_options>
* on every comment.
* and <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#style_shortcuts>.
*/
// absolute: {
week: function (then) { return then.calendar(); },
// dateStyle: "long",
// timeStyle: "short",
/**
// },
* The calendar() method uses an ambiguous “MM/DD/YYYY” format for
* faraway dates; spell things out for this international audience.
*/
other: function (then) {
var pref = mw.user.options.values.date;
return then.format(window.LocalComments.formatOptions[pref] || "LLL");
},
},
Line 62 ⟶ 67:
* Formats to display in each timestamp’s tooltip, one per line.
*
* If an element of this array is aan string,object theits timestamp`type` isand formatted`options` may be:
*
* according to the documentation at
* `type` | `options`
* <http://momentjs.com/docs/#/displaying/format/>.
* ------------|----------
* `relative` | `Intl.RelativeTimeFormat` options
* `absolute` | `Intl.AbsoluteTimeFormat` options
* `mediawiki` | —
* `iso8601` | —
*
* See:
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat/RelativeTimeFormat#options>
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#date-time_component_options>
* <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat/DateTimeFormat#style_shortcuts>
*
* If an element of this array is a function, it is called to retrieve the
* formatted timestamp string. SeeThe <http://momentjs.com/docs/#/displaying/>function must accept one argument, a
* `Date` object.
* for the various things you can do with the passed-in moment object.
*/
tooltipComponents: [
tooltipFormats: [
{
function (then) { return then.fromNow(); },
type: "LLLLrelative",
options: {
"YYYY-MM-DDTHH:mmZ",
numeric: "auto",
},
},
{
type: "absolute",
options: {
dateStyle: "full",
timeStyle: "short",
},
},
{
type: "iso8601",
},
],
Line 102 ⟶ 130:
*/
codeTags: ["code", "input", "pre", "textarea"],
/**
* An object mapping the date format user options provided by this MediaWiki
* installation to corresponding Moment.js format strings. The user can
* choose a preferred date format in
* [[Special:Preferences#mw-prefsection-rendering-dateformat]]. See
* [[mw:Manual:Date formatting]]. These formats determine the default
* timestamp display format.
*
* These formats come from
* <https://doc.wikimedia.org/mediawiki-core/1.34.0/php/MessagesEn_8php.html#a2fc93ea5327f655d3ed306e221ee33f0>.
* When customizing these formats for a different wiki’s content language,
* consult the language’s corresponding message file’s `$dateFormats`
* variable. Use only the messages with the “both” suffix, and remove that
* suffix from each key. The MediaWiki date format syntax is described in
* <https://doc.wikimedia.org/mediawiki-core/1.34.0/php/classLanguage.html#a94f84f82d7f954c4cb2e191d22c6e6a6>
* and [[mw:Help:Extension:ParserFunctions##time]]. The Moment.js syntax is
* described in <https://momentjs.com/docs/#/parsing/string-format/>.
*
* @todo Automatically convert MediaWiki date format syntax to Moment.js
* date format syntax.
*/
formatOptions: {
mdy: "HH:mm, MMMM D, YYYY", // H:i, F j, Y
dmy: "HH:mm, D MMMM YYYY", // H:i, j F Y
ymd: "HH:mm, YYYY MMMM D", // H:i, Y F j
"ISO 8601": "YYYY-MM-DDTHH:mm:ss", // xnY-xnm-xnd"T"xnH:xni:xns
},
/**
* Expected format or formats of the timestamps in existing wikitext. If
* very different formats have been used over the course of the wiki’s
* history, specify an array of formats.
*
* This option expects parsing format strings
* <http://momentjs.com/docs/#/parsing/string-format/>.
*/
parseFormat: "H:m, D MMM YYYY",
/**
* Regular expression matching all the timestamps inserted by this MediaWiki
* installation over the years. This regular expression shouldincludes morethe or lessnamed
* capturing groups `hours`, `minutes`, `day`, `month`, `year`, and
* agree with the parseFormat option.
* `timezone`.
*
* Until 2005:
Line 151 ⟶ 142:
* 08:51, 23 November 2015 (UTC)
*/
parseRegExp: /(?<hours>\d\d):(?<minutes>\d\d), (?<day>\d\d?) (?<month>(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\w*) (?<year>\d{4}) \((?<timezone>UTC)\)/,
/**
Line 195 ⟶ 186:
var prefixNode;
while ((prefixNode = iter.nextNode())) {
var then;
var dateNode;
var result = LocalComments.parseRegExp.exec(prefixNode.data);
if (!result) continue;{
// Split out the timestamp into a separate text node.
dateNode = prefixNode.splitText(result.index);
// Split out the timestamp into a separate text node.
var dateNodesuffixNode = prefixNodedateNode.splitText(result[0].indexlength);
var suffixNode = dateNode.splitText(result[0].length);
// Determine the represented time.
var components = result.groups;
// Determine the represented time.
var monthIndex = mw.config.get("wgMonthNames").slice(1).indexOf(components.month);
var then = moment.utc(result[0], LocalComments.parseFormat);
if (!then.isValid()) {
// Many Wikipedias started out with English as the default
// localization, so fall back to English.
if (monthIndex === -1) {
then = moment.utc(result[0], "H:m, D MMM YYYY", "en");
monthIndex = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"].indexOf(components.month);
}
if (monthIndex === -1) {
monthIndex = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"].indexOf(components.month);
}
if (monthIndex !== -1) {
var offsetHours = components.hours - LocalComments.utcOffset;
var minuteOffset = (LocalComments.utcOffset - Math.round(LocalComments.utcOffset)) % 60;
var offsetMinutes = components.minutes - minuteOffset;
then = new Date(Date.UTC(components.year, monthIndex, components.day, offsetHours, offsetMinutes));
}
}
Line 217 ⟶ 220:
// [[User talk:Mxn/CommentsInLocalTime.js#Interface-protected edit request on 18 November 2022]]
var timeElt = $("<time />");
if (then.isValid!isNaN(then)) {
then.utcOffset(-LocalComments.utcOffset);
// MediaWiki core styles .explain[title] the same way as
// abbr[title], guiding the user to the tooltip.
Line 224 ⟶ 226:
timeElt.attr("datetime", then.toISOString());
}
if (dateNode) $(dateNode).wrap(timeElt);
}
}
/**
* Returns athe formattedcoarsest stringrelative fordate thecomponent giventhat datefits within the object.time
* elapsed between the given date and the current date.
*
* @param {Date} then The date object tobefore formator after the current date.
* @returns {Object} An object indicating the date component’s value and
* @param {String} fmt A format string or function.
* unit compatible with `Intl.RelativeTimeFormat`.
* @returns {String} A formatted string.
*/
function formatDaterelativeDateComponent(then, fmt) {
if (fmt instanceof Function) {
return fmt(then);
} else {
}
}
/**
* Reformats a timestamp marked up with the <time> element.
*
* @param {Number} idx Unused.
* @param {Element} elt The <time> element.
*/
function formatTimestamp(idx, elt) {
var iso = $(elt).attr("datetime");
var then = new Date(Date.parse(iso));
var now = new Date();
var formats = LocalComments.formats;
var lang = mw.config.get("wgPageViewLanguage");
// Add a tooltip with multiple formats.
elt.title = $.map(LocalComments.tooltipFormats, function (fmt, idx) {
return formatDate(then, fmt);
}).join("\n");
// Register for periodic updates.
var value;
var unit;
var seconds = (nowthen - thennow) / 1000; // convert ms to s
value = seconds;
unit = "seconds";
var minutes = seconds / 60;
if (Math.abs(seconds) > 45) { // moment.relativeTimeThreshold("s")
Line 272 ⟶ 251:
unit = "minutes";
}
var hours = minutes / 60;
if (Math.abs(minutes) > 45) { // moment.relativeTimeThreshold("m")
Line 277 ⟶ 257:
unit = "hours";
}
var days = hours / 24;
if (Math.abs(hours) > 22) { // moment.relativeTimeThreshold("h")
Line 282 ⟶ 263:
unit = "days";
}
var weeks = days / 7;
if (Math.abs(days) > 7) {
Line 287 ⟶ 269:
unit = "weeks";
}
$(elt).attr("data-localcomments-unit", unit);
return {
value: Math.round(value),
unit: unit,
};
}
/**
* Returns a formatted string for the given date object.
*
* @param {Date} then The date object to format.
* @param {String} fmt A format string or function.
* @returns {String} A formatted string.
*/
function formatDate(then, fmt) {
if (fmt instanceof Function) {
return fmt(then);
}
var lang = mw.config.get("wgPageViewLanguage");
var formatter = mw.loader.require("mediawiki.DateFormatter");
switch (fmt.type) {
case "absolute":
if (fmt.options) {
var absolute = new Intl.DateTimeFormat(lang, fmt.options);
return absolute.format(then);
}
return formatter.formatTimeAndDate(then);
case "relative":
if (fmt.options) {
var relative = new Intl.RelativeTimeFormat(lang, fmt.options);
var component = relativeDateComponent(then);
return relative.format(component.value, component.unit);
}
return formatter.formatRelativeTimeOrDate(then);
case "iso8601":
return formatter.formatIso(then);
}
}
/**
* Reformats a timestamp marked up with the <time> element.
*
* @param {Number} idx Unused.
* @param {Element} elt The <time> element.
*/
function formatTimestamp(idx, elt) {
var iso = elt.dateTime;
if (!iso) {
return;
}
var then = new Date(Date.parse(iso));
// Add a tooltip with multiple formats.
elt.title = $.map(LocalComments.tooltipComponents, function (fmt, idx) {
return formatDate(then, fmt) || "";
}).join("\n");
// Replace the text.
var text = formatDate(then, {type: "relative"});
var format;
varif (text;) {
$(elt).text(text);
if (unit === "weeks") {
format = new Intl.DateTimeFormat(lang, {dateStyle: "long", timeStyle: "short"});
text = format.format(then);
} else {
format = new Intl.RelativeTimeFormat(lang, {numeric: "auto"});
text = format.format(Math.round(value), unit);
}
$(elt).text(text);
// Register for periodic updates.
var component = relativeDateComponent(then);
$(elt).attr("data-localcomments-unit", component.unit);
}
Line 331 ⟶ 369:
}
wrapTimestamps();
mw.loader.using("moment", function () {
mw.loader.using("mediawiki.DateFormatter", function () {
wrapTimestamps();
formatTimestamps();
});