diff --git a/frontend_tests/node_tests/timerender.js b/frontend_tests/node_tests/timerender.js index d28db882b6..ee4c26e7b4 100644 --- a/frontend_tests/node_tests/timerender.js +++ b/frontend_tests/node_tests/timerender.js @@ -219,24 +219,59 @@ run_test("absolute_time_24_hour", () => { assert.equal(actual, expected); }); -run_test("set_full_datetime", () => { - const message = { - timestamp: 1495091573, // 2017/5/18 7:12:53 AM (UTC+0) - }; +function test_set_full_datetime(message, expected_tooltip_content) { const time_element = $(""); const attrs = {}; - time_element.attr = (name, val) => { + time_element.attr = (name, val = null) => { + if (val === null) { + return attrs[name]; + } attrs[name] = val; - return time_element; + return val; + }; + + timerender.set_full_datetime(message, time_element); + assert.equal(attrs["data-tippy-content"], expected_tooltip_content); + + // Removing `data-tippy-content` and re-running should + // set `data-tippy-content` value again. + delete attrs["data-tippy-content"]; + timerender.set_full_datetime(message, time_element); + assert.equal(attrs["data-tippy-content"], expected_tooltip_content); +} + +run_test("set_full_datetime", () => { + let message = { + timestamp: 1495091573, // 2017/5/18 7:12:53 AM (UTC+0) }; // The formatting of the string time.toLocale(Date|Time)String() on Node // might differ from the browser. - const time = new Date(message.timestamp * 1000); - const expected = `${time.toLocaleDateString()} 7:12:53 AM (UTC+0)`; - timerender.set_full_datetime(message, time_element); - assert.equal(attrs.title, expected); + let time = new Date(message.timestamp * 1000); + let expected = `${time.toLocaleDateString("en", { + weekday: "long", + month: "long", + day: "numeric", + year: "numeric", + })}
7:12:53 AM Coordinated Universal Time`; + test_set_full_datetime(message, expected); + + // Check year is hidden if current year. + time = new Date(); + message = { + timestamp: Math.floor(time.getTime() / 1000), + }; + // Also check 24hour time format is shown. + page_params.twenty_four_hour_time = true; + const date_string = time.toLocaleDateString("en", { + weekday: "long", + month: "long", + day: "numeric", + }); + const time_string = time.toLocaleString("en", {timeStyle: "full", hourCycle: "h24"}); + expected = `${date_string}
${time_string}`; + test_set_full_datetime(message, expected); }); run_test("last_seen_status_from_date", () => { diff --git a/static/js/timerender.js b/static/js/timerender.js index 0eb7e83a96..f4295873ce 100644 --- a/static/js/timerender.js +++ b/static/js/timerender.js @@ -307,29 +307,38 @@ export const absolute_time = (function () { })(); export function get_full_datetime(time) { - // Convert to number of hours ahead/behind UTC. - // The sign of getTimezoneOffset() is reversed wrt - // the conventional meaning of UTC+n / UTC-n - const tz_offset = -time.getTimezoneOffset() / 60; + const date_string_options = {weekday: "long", month: "long", day: "numeric"}; + const time_string_options = {timeStyle: "full"}; + + if (page_params.twenty_four_hour_time) { + time_string_options.hourCycle = "h24"; + } + + const current_date = new Date(); + if (time.getFullYear() !== current_date.getFullYear()) { + // Show year only if not current year. + date_string_options.year = "numeric"; + } + return { - date: time.toLocaleDateString(), - time: time.toLocaleTimeString() + " (UTC" + (tz_offset < 0 ? "" : "+") + tz_offset + ")", + date: time.toLocaleDateString(page_params.request_language, date_string_options), + time: time.toLocaleTimeString(page_params.request_language, time_string_options), }; } +function render_tippy_tooltip(message, time_elem) { + time_elem.attr("data-tippy-content", message.full_date_str + "
" + message.full_time_str); +} + // Date.toLocaleDateString and Date.toLocaleTimeString are // expensive, so we delay running the following code until we need // the full date and time strings. export const set_full_datetime = function timerender_set_full_datetime(message, time_elem) { - if (message.full_date_str !== undefined) { - return; - } - const time = new Date(message.timestamp * 1000); const full_datetime = get_full_datetime(time); message.full_date_str = full_datetime.date; message.full_time_str = full_datetime.time; - time_elem.attr("title", message.full_date_str + " " + message.full_time_str); + render_tippy_tooltip(message, time_elem); }; diff --git a/static/js/tippyjs.js b/static/js/tippyjs.js index aaead56882..41c751ee97 100644 --- a/static/js/tippyjs.js +++ b/static/js/tippyjs.js @@ -145,4 +145,14 @@ export function initialize() { return true; }, }); + + delegate("body", { + target: ".message_time", + allowHTML: true, + placement: "top", + appendTo: () => document.body, + onHidden(instance) { + instance.destroy(); + }, + }); }