timestamp: Change syntax to `<time:timestammp>`.

We had been using !time() syntax for timestamps so far. Since its
an unreleased feature, we can make changes without affecting many
people.

Fixes #15442.
This commit is contained in:
Rohitt Vashishtha 2020-07-06 20:03:14 +05:30 committed by Tim Abbott
parent ca73d81bba
commit 732ec3c0e6
6 changed files with 34 additions and 35 deletions

View File

@ -1302,14 +1302,14 @@ run_test('begins_typeahead', () => {
assert_typeahead_equals("#**Sweden>totally new topic", sweden_topics_to_show);
// time_jump
assert_typeahead_equals("!tim", false);
assert_typeahead_equals("!timerandom", false);
assert_typeahead_equals("!time", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("!time(", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("!time(something", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("!time(something", ") ", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("!time(something)", false);
assert_typeahead_equals("!time(something) ", false); // Already completed the mention
assert_typeahead_equals("<tim", false);
assert_typeahead_equals("<timerandom", false);
assert_typeahead_equals("<time", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("<time:", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("<time:something", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("<time:something", "> ", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("<time:something>", ['translated: Mention a timezone-aware time']);
assert_typeahead_equals("<time:something> ", false); // Already completed the mention
// Following tests place the cursor before the second string
assert_typeahead_equals("#test", "ing", false);
@ -1317,7 +1317,7 @@ run_test('begins_typeahead', () => {
assert_typeahead_equals(":test", "ing", false);
assert_typeahead_equals("```test", "ing", false);
assert_typeahead_equals("~~~test", "ing", false);
const terminal_symbols = ',.;?!()[] "\'\n\t';
const terminal_symbols = ',.;?!()[]> "\'\n\t';
terminal_symbols.split().forEach((symbol) => {
assert_stream_list("#test", symbol);
assert_typeahead_equals("@test", symbol, all_mentions);

View File

@ -331,7 +331,7 @@ exports.tokenize_compose_str = function (s) {
}
}
const timestamp_index = s.indexOf('!time');
const timestamp_index = s.indexOf('<time');
if (timestamp_index >= 0) {
return s.slice(timestamp_index);
}
@ -607,7 +607,7 @@ exports.get_candidates = function (query) {
// already-completed object.
// We will likely want to extend this list to be more i18n-friendly.
const terminal_symbols = ',.;?!()[] "\'\n\t';
const terminal_symbols = ',.;?!()[]> "\'\n\t';
if (rest !== '' && !terminal_symbols.includes(rest[0])) {
return false;
}
@ -736,11 +736,10 @@ exports.get_candidates = function (query) {
}
}
if (this.options.completions.timestamp) {
const time_jump_regex = /!time(\(([^\)]*?))?$/;
const time_jump_regex = /<time(\:([^>]*?)>?)?$/;
if (time_jump_regex.test(split[0])) {
this.completing = 'time_jump';
return [i18n.t('Mention a timezone-aware time')];
}
}
return false;
@ -885,9 +884,9 @@ exports.content_typeahead_selected = function (item, event) {
const start = beginning.length - this.token.length;
beginning = beginning.substring(0, start) + item + '** ';
} else if (this.completing === 'time_jump') {
let timestring = beginning.substring(beginning.lastIndexOf('!time'));
let timestring = beginning.substring(beginning.lastIndexOf('<time:'));
let default_timestamp;
if (timestring.startsWith('!time(') && timestring.endsWith(')')) {
if (timestring.startsWith('<time:') && timestring.endsWith('>')) {
timestring = timestring.substring(6, timestring.length - 1);
moment.suppressDeprecationWarnings = true;
try {
@ -901,8 +900,8 @@ exports.content_typeahead_selected = function (item, event) {
const on_timestamp_selection = (val) => {
const datestr = val;
beginning = beginning.substring(0, beginning.lastIndexOf('!time')) + `!time(${datestr}) `;
if (rest.startsWith(')')) {
beginning = beginning.substring(0, beginning.lastIndexOf('<time')) + `<time:${datestr}> `;
if (rest.startsWith('>')) {
rest = rest.slice(1);
}
textbox.val(beginning + rest);

View File

@ -164,7 +164,7 @@ exports.render_date = function (time, time_above, today) {
return node;
};
// Renders the timestamp returned by the !time() markdown syntax.
// Renders the timestamp returned by the <time:> markdown syntax.
exports.render_markdown_timestamp = function (time, now, text) {
now = now || moment();
if (page_params.timezone) {

View File

@ -553,7 +553,7 @@ inline.zulip = merge({}, inline.breaks, {
avatar: /^!avatar\(([^)]+)\)/,
gravatar: /^!gravatar\(([^)]+)\)/,
tex: /^(\$\$([^\n_$](\\\$|[^\n$])*)\$\$(?!\$))\B/,
timestamp: /^!time\(([^)]+)\)/,
timestamp: /^<time:([^>]+)>/,
realm_filters: [],
text: replace(inline.breaks.text)
('|', '|(\ud83c[\udd00-\udfff]|\ud83d[\udc00-\ude4f]|' +
@ -692,6 +692,13 @@ InlineLexer.prototype.output = function(src) {
continue;
}
// timestamp
if (cap = this.rules.timestamp.exec(src)) {
src = src.substring(cap[0].length);
out += this.timestamp(cap[1]);
continue;
}
// tag
if (cap = this.rules.tag.exec(src)) {
if (!this.inLink && /^<a /i.test(cap[0])) {
@ -828,13 +835,6 @@ InlineLexer.prototype.output = function(src) {
continue;
}
// timestamp
if (cap = this.rules.timestamp.exec(src)) {
src = src.substring(cap[0].length);
out += this.timestamp(cap[1]);
continue;
}
// tex
if (cap = this.rules.tex.exec(src)) {
src = src.substring(cap[0].length);
@ -911,7 +911,7 @@ InlineLexer.prototype.userGravatar = function (email) {
InlineLexer.prototype.timestamp = function (time) {
if (typeof this.options.timestampHandler !== 'function')
return '!time(' + time + ')';
return '&lt;time:' + time + '&gt;';
return this.options.timestampHandler(time);
};

View File

@ -1941,7 +1941,7 @@ class Markdown(markdown.Markdown):
reg.register(StreamTopicPattern(get_compiled_stream_topic_link_regex(), self), 'topic', 87)
reg.register(StreamPattern(get_compiled_stream_link_regex(), self), 'stream', 85)
reg.register(Avatar(AVATAR_REGEX, self), 'avatar', 80)
reg.register(Timestamp(r'!time\((?P<time>[^)]*)\)'), 'timestamp', 75)
reg.register(Timestamp(r'<time:(?P<time>[^>]*?)>'), 'timestamp', 75)
# Note that !gravatar syntax should be deprecated long term.
reg.register(Avatar(GRAVATAR_REGEX, self), 'gravatar', 70)
reg.register(UserGroupMentionPattern(mention.user_group_mentions, self), 'usergroupmention', 65)

View File

@ -748,34 +748,34 @@
},
{
"name": "timestamp_backend_markdown_only",
"input": "!time(Jun 5th 2017, 10:30PM)",
"input": "<time:Jun 5th 2017, 10:30PM>",
"expected_output": "<p><time datetime=\"2017-06-05T22:30:00Z\">Jun 5th 2017, 10:30PM</time></p>",
"marked_expected_output": "<p><span class=\"timestamp-error\">Invalid time format: Jun 5th 2017, 10:30PM</span></p>"
},
{
"name": "timestamp_backend_markdown_and_marked",
"input": "!time(31 Dec 2017)",
"input": "<time:31 Dec 2017>",
"expected_output": "<p><time datetime=\"2017-12-31T00:00:00Z\">31 Dec 2017</time></p>"
},
{
"name": "timestamp_invalid_input",
"input": "!time(<alert(1)>)",
"expected_output": "<p><span class=\"timestamp-error\">Invalid time format: &lt;alert(1</span>&gt;)</p>"
"input": "<time:<alert(1)>>",
"expected_output": "<p><span class=\"timestamp-error\">Invalid time format: &lt;alert(1)</span>&gt;</p>"
},
{
"name": "timestamp_timezone",
"input": "!time(31 Dec 2017 5:30 am IST)",
"input": "<time:31 Dec 2017 5:30 am IST>",
"expected_output": "<p><time datetime=\"2017-12-31T00:00:00Z\">31 Dec 2017 5:30 am IST</time></p>",
"marked_expected_output": "<p><span class=\"timestamp-error\">Invalid time format: 31 Dec 2017 5:30 am IST</span></p>"
},
{
"name": "timestamp_incorrect",
"input": "!time(**hello world**)",
"input": "<time:**hello world**>",
"expected_output": "<p><span class=\"timestamp-error\">Invalid time format: **hello world**</span></p>"
},
{
"name": "timestamp_unix",
"input": "!time(1496701800)",
"input": "<time:1496701800>",
"expected_output": "<p><time datetime=\"2017-06-05T22:30:00Z\">1496701800</time></p>"
},
{