2019-01-28 15:41:33 +01:00
|
|
|
set_global('$', global.make_zjquery());
|
2017-08-09 18:28:34 +02:00
|
|
|
zrequire('hash_util');
|
|
|
|
zrequire('hashchange');
|
|
|
|
zrequire('narrow_state');
|
|
|
|
zrequire('people');
|
|
|
|
zrequire('stream_data');
|
|
|
|
zrequire('Filter', 'js/filter');
|
2019-01-28 17:44:48 +01:00
|
|
|
set_global('page_params', {
|
|
|
|
stop_words: ['what', 'about'],
|
|
|
|
});
|
2020-04-13 18:53:07 +02:00
|
|
|
set_global('resize', {
|
|
|
|
resize_page_components: () => {},
|
|
|
|
resize_stream_filters_container: () => {},
|
|
|
|
});
|
|
|
|
|
2013-08-09 02:05:23 +02:00
|
|
|
|
2017-08-09 18:28:34 +02:00
|
|
|
zrequire('narrow');
|
2017-04-25 15:25:31 +02:00
|
|
|
|
2013-09-18 19:01:21 +02:00
|
|
|
function set_filter(operators) {
|
2020-07-02 01:39:34 +02:00
|
|
|
operators = operators.map((op) => ({
|
js: Convert _.map(a, …) to a.map(…).
And convert the corresponding function expressions to arrow style
while we’re here.
import * as babelParser from "recast/parsers/babel";
import * as recast from "recast";
import * as tsParser from "recast/parsers/typescript";
import { builders as b, namedTypes as n } from "ast-types";
import K from "ast-types/gen/kinds";
import fs from "fs";
import path from "path";
import process from "process";
const checkExpression = (node: n.Node): node is K.ExpressionKind =>
n.Expression.check(node);
for (const file of process.argv.slice(2)) {
console.log("Parsing", file);
const ast = recast.parse(fs.readFileSync(file, { encoding: "utf8" }), {
parser: path.extname(file) === ".ts" ? tsParser : babelParser,
});
let changed = false;
recast.visit(ast, {
visitCallExpression(path) {
const { callee, arguments: args } = path.node;
if (
n.MemberExpression.check(callee) &&
!callee.computed &&
n.Identifier.check(callee.object) &&
callee.object.name === "_" &&
n.Identifier.check(callee.property) &&
callee.property.name === "map" &&
args.length === 2 &&
checkExpression(args[0]) &&
checkExpression(args[1])
) {
const [arr, fn] = args;
path.replace(
b.callExpression(b.memberExpression(arr, b.identifier("map")), [
n.FunctionExpression.check(fn) ||
n.ArrowFunctionExpression.check(fn)
? b.arrowFunctionExpression(
fn.params,
n.BlockStatement.check(fn.body) &&
fn.body.body.length === 1 &&
n.ReturnStatement.check(fn.body.body[0])
? fn.body.body[0].argument || b.identifier("undefined")
: fn.body
)
: fn,
])
);
changed = true;
}
this.traverse(path);
},
});
if (changed) {
console.log("Writing", file);
fs.writeFileSync(file, recast.print(ast).code, { encoding: "utf8" });
}
}
Signed-off-by: Anders Kaseorg <anders@zulipchat.com>
2020-02-08 02:43:49 +01:00
|
|
|
operator: op[0],
|
|
|
|
operand: op[1],
|
|
|
|
}));
|
2017-04-25 15:25:31 +02:00
|
|
|
narrow_state.set_current_filter(new Filter(operators));
|
2013-09-18 19:01:21 +02:00
|
|
|
}
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const me = {
|
2018-10-18 19:41:44 +02:00
|
|
|
email: 'me@example.com',
|
|
|
|
user_id: 5,
|
|
|
|
full_name: 'Me Myself',
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const alice = {
|
2018-05-28 14:10:33 +02:00
|
|
|
email: 'alice@example.com',
|
|
|
|
user_id: 23,
|
|
|
|
full_name: 'Alice Smith',
|
|
|
|
};
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const ray = {
|
2018-05-28 14:10:33 +02:00
|
|
|
email: 'ray@example.com',
|
|
|
|
user_id: 22,
|
|
|
|
full_name: 'Raymond',
|
|
|
|
};
|
|
|
|
|
2018-05-15 12:40:07 +02:00
|
|
|
run_test('uris', () => {
|
2020-05-26 22:34:15 +02:00
|
|
|
people.add_active_user(ray);
|
|
|
|
people.add_active_user(alice);
|
|
|
|
people.add_active_user(me);
|
2018-10-18 19:41:44 +02:00
|
|
|
people.initialize_current_user(me.user_id);
|
2017-01-06 14:42:52 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let uri = hash_util.pm_with_uri(ray.email);
|
Make nicer slugs for "pm-with" narrows.
The slugs for PM-with narrows now have user ids in them, so they
are more resilient to email changes, and they have less escaping
characters and are generally prettier.
Examples:
narrow/pm-with/3-cordelia
narrow/pm-with/3,5-group
The part of the URL that is actionable is the comma-delimited
list of one or more userids.
When we decode the slugs, we only use the part before the dash; the
stuff after the dash is just for humans. If we don't see a number
before the dash, we fall back to the old decoding (which should only
matter during a transition period where folks may have old links).
For group PMS, we always say "group" after the dash. For single PMs,
we use the person's email userid, since it's usually fairly concise
and not noisy for a URL. We may tinker with this later.
Basically, the heart of this change is these two new methods:
people.emails_to_slug
people.slug_to_emails
And then we unify the encode codepath as follows:
narrow.pm_with_uri ->
hashchange.operators_to_hash ->
hashchange.encode_operand ->
people.emails_to_slug
The decode path didn't really require much modication in this commit,
other than to have hashchange.decode_operand call people.slug_to_emails
for the pm-with case.
2017-01-06 02:00:03 +01:00
|
|
|
assert.equal(uri, '#narrow/pm-with/22-ray');
|
2017-01-06 14:42:52 +01:00
|
|
|
|
2018-08-04 16:52:37 +02:00
|
|
|
uri = hash_util.huddle_with_uri("22,23");
|
2017-01-06 14:42:52 +01:00
|
|
|
assert.equal(uri, '#narrow/pm-with/22,23-group');
|
|
|
|
|
2018-08-04 17:19:03 +02:00
|
|
|
uri = hash_util.by_sender_uri(ray.email);
|
2017-01-19 03:53:50 +01:00
|
|
|
assert.equal(uri, '#narrow/sender/22-ray');
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
let emails = global.hash_util.decode_operand('pm-with', '22,23-group');
|
2017-01-06 14:42:52 +01:00
|
|
|
assert.equal(emails, 'alice@example.com,ray@example.com');
|
2018-10-18 19:41:44 +02:00
|
|
|
|
|
|
|
emails = global.hash_util.decode_operand('pm-with', '5,22,23-group');
|
|
|
|
assert.equal(emails, 'alice@example.com,ray@example.com');
|
|
|
|
|
|
|
|
emails = global.hash_util.decode_operand('pm-with', '5-group');
|
|
|
|
assert.equal(emails, 'me@example.com');
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|
2017-01-25 19:13:10 +01:00
|
|
|
|
2018-05-15 12:40:07 +02:00
|
|
|
run_test('show_empty_narrow_message', () => {
|
2017-04-25 15:25:31 +02:00
|
|
|
narrow_state.reset_current_filter();
|
2017-01-25 19:13:10 +01:00
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert.equal($('.empty_feed_notice').visible(), false);
|
|
|
|
assert($('#empty_narrow_message').visible());
|
|
|
|
assert.equal(
|
|
|
|
$('#left_bar_compose_reply_button_big').attr('title'),
|
|
|
|
'translated: There are no messages to reply to.'
|
|
|
|
);
|
2017-01-25 19:13:10 +01:00
|
|
|
|
|
|
|
// for non-existent or private stream
|
|
|
|
set_filter([['stream', 'Foo']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#nonsubbed_private_nonexistent_stream_narrow_message').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
|
|
|
// for non sub public stream
|
2020-02-09 22:02:55 +01:00
|
|
|
stream_data.add_sub({name: 'ROME', stream_id: 99});
|
2019-03-08 22:31:09 +01:00
|
|
|
stream_data.update_calculated_fields(stream_data.get_sub("ROME"));
|
2017-01-25 19:13:10 +01:00
|
|
|
set_filter([['stream', 'Rome']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#nonsubbed_stream_narrow_message').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
|
|
|
set_filter([['is', 'starred']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#empty_star_narrow_message').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
|
|
|
set_filter([['is', 'mentioned']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#empty_narrow_all_mentioned').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
|
|
|
set_filter([['is', 'private']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#empty_narrow_all_private_message').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
2017-06-18 23:50:00 +02:00
|
|
|
set_filter([['is', 'unread']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#no_unread_narrow_message').visible());
|
2017-06-18 23:50:00 +02:00
|
|
|
|
2018-05-28 14:10:33 +02:00
|
|
|
set_filter([['pm-with', ['Yo']]]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#non_existing_user').visible());
|
2018-05-28 14:10:33 +02:00
|
|
|
|
2020-05-26 22:34:15 +02:00
|
|
|
people.add_active_user(alice);
|
2017-01-25 19:13:10 +01:00
|
|
|
set_filter([['pm-with', ['alice@example.com', 'Yo']]]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#non_existing_users').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
|
|
|
set_filter([['pm-with', 'alice@example.com']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#empty_narrow_private_message').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
2017-09-24 19:26:51 +02:00
|
|
|
set_filter([['group-pm-with', 'alice@example.com']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#empty_narrow_group_private_message').visible());
|
2017-09-24 19:26:51 +02:00
|
|
|
|
2017-01-25 19:13:10 +01:00
|
|
|
set_filter([['sender', 'ray@example.com']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#silent_user').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
|
|
|
set_filter([['sender', 'sinwar@example.com']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#non_existing_user').visible());
|
2017-01-25 19:13:10 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const display = $("#empty_search_stop_words_string");
|
2019-01-28 17:44:48 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const items = [];
|
2019-01-28 17:44:48 +01:00
|
|
|
display.append = (html) => {
|
|
|
|
items.push(html);
|
|
|
|
};
|
|
|
|
|
2017-01-25 19:13:10 +01:00
|
|
|
set_filter([['search', 'grail']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
2019-01-28 15:41:33 +01:00
|
|
|
assert($('#empty_search_narrow_message').visible());
|
2019-01-28 17:44:48 +01:00
|
|
|
|
|
|
|
assert.equal(items.length, 2);
|
|
|
|
assert.equal(items[0], ' ');
|
|
|
|
assert.equal(items[1].text(), 'grail');
|
2019-03-07 09:27:45 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
run_test('show_search_stopwords', () => {
|
|
|
|
narrow_state.reset_current_filter();
|
2019-11-02 00:06:25 +01:00
|
|
|
let items = [];
|
2019-03-07 09:27:45 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const display = $("#empty_search_stop_words_string");
|
2019-01-28 17:44:48 +01:00
|
|
|
|
|
|
|
display.append = (html) => {
|
|
|
|
if (html.text) {
|
|
|
|
items.push(html.selector + html.text());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
set_filter([['search', 'what about grail']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
|
|
|
assert($('#empty_search_narrow_message').visible());
|
|
|
|
|
|
|
|
assert.equal(items.length, 3);
|
|
|
|
assert.equal(items[0], '<del>what');
|
|
|
|
assert.equal(items[1], '<del>about');
|
|
|
|
assert.equal(items[2], '<span>grail');
|
2019-03-07 09:27:45 +01:00
|
|
|
|
|
|
|
items = [];
|
|
|
|
set_filter([['stream', 'streamA'], ['search', 'what about grail']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
|
|
|
assert($('#empty_search_narrow_message').visible());
|
|
|
|
|
|
|
|
assert.equal(items.length, 4);
|
|
|
|
assert.equal(items[0], '<span>stream: streamA');
|
|
|
|
assert.equal(items[1], '<del>what');
|
|
|
|
assert.equal(items[2], '<del>about');
|
|
|
|
assert.equal(items[3], '<span>grail');
|
|
|
|
|
|
|
|
items = [];
|
|
|
|
set_filter([['stream', 'streamA'], ['topic', 'topicA'], ['search', 'what about grail']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
|
|
|
assert($('#empty_search_narrow_message').visible());
|
|
|
|
|
|
|
|
assert.equal(items.length, 4);
|
|
|
|
assert.equal(items[0], '<span>stream: streamA topic: topicA');
|
|
|
|
assert.equal(items[1], '<del>what');
|
|
|
|
assert.equal(items[2], '<del>about');
|
|
|
|
assert.equal(items[3], '<span>grail');
|
2018-05-15 12:40:07 +02:00
|
|
|
});
|
2018-11-30 00:20:10 +01:00
|
|
|
|
2019-03-07 09:12:00 +01:00
|
|
|
run_test('show_invalid_narrow_message', () => {
|
|
|
|
narrow_state.reset_current_filter();
|
2019-11-02 00:06:25 +01:00
|
|
|
const display = $("#empty_search_stop_words_string");
|
2019-03-07 09:12:00 +01:00
|
|
|
|
2020-02-09 22:02:55 +01:00
|
|
|
stream_data.add_sub({name: 'streamA', stream_id: 88});
|
|
|
|
stream_data.add_sub({name: 'streamB', stream_id: 77});
|
2019-03-07 09:12:00 +01:00
|
|
|
|
|
|
|
set_filter([['stream', 'streamA'], ['stream', 'streamB']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
|
|
|
assert($('#empty_search_narrow_message').visible());
|
|
|
|
assert.equal(display.text(), 'translated: You are searching for messages that belong to more than one stream, which is not possible.');
|
|
|
|
|
|
|
|
set_filter([['topic', 'topicA'], ['topic', 'topicB']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
|
|
|
assert($('#empty_search_narrow_message').visible());
|
|
|
|
assert.equal(display.text(), 'translated: You are searching for messages that belong to more than one topic, which is not possible.');
|
|
|
|
|
2020-05-26 22:34:15 +02:00
|
|
|
people.add_active_user(ray);
|
|
|
|
people.add_active_user(alice);
|
2019-03-07 09:12:00 +01:00
|
|
|
|
|
|
|
set_filter([['sender', 'alice@example.com'], ['sender', 'ray@example.com']]);
|
|
|
|
narrow.show_empty_narrow_message();
|
|
|
|
assert($('#empty_search_narrow_message').visible());
|
|
|
|
assert.equal(display.text(), 'translated: You are searching for messages that are sent by more than one person, which is not possible.');
|
|
|
|
});
|
|
|
|
|
2018-11-30 00:20:10 +01:00
|
|
|
run_test('narrow_to_compose_target', () => {
|
|
|
|
set_global('compose_state', {});
|
2020-03-22 18:40:05 +01:00
|
|
|
set_global('stream_topic_history', {});
|
2018-11-30 00:20:10 +01:00
|
|
|
const args = {called: false};
|
|
|
|
const activate_backup = narrow.activate;
|
|
|
|
narrow.activate = function (operators, opts) {
|
|
|
|
args.operators = operators;
|
|
|
|
args.opts = opts;
|
|
|
|
args.called = true;
|
|
|
|
};
|
|
|
|
|
|
|
|
// No-op when not composing.
|
|
|
|
global.compose_state.composing = () => false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, false);
|
|
|
|
global.compose_state.composing = () => true;
|
|
|
|
|
|
|
|
// No-op when empty stream.
|
|
|
|
global.compose_state.get_message_type = () => 'stream';
|
|
|
|
global.compose_state.stream_name = () => '';
|
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, false);
|
|
|
|
|
|
|
|
// --- Tests for stream messages ---
|
|
|
|
global.compose_state.get_message_type = () => 'stream';
|
2020-02-09 22:02:55 +01:00
|
|
|
stream_data.add_sub({name: 'ROME', stream_id: 99});
|
2018-11-30 00:20:10 +01:00
|
|
|
global.compose_state.stream_name = () => 'ROME';
|
2020-03-22 18:40:05 +01:00
|
|
|
global.stream_topic_history.get_recent_topic_names = () => ['one', 'two', 'three'];
|
2018-11-30 00:20:10 +01:00
|
|
|
|
|
|
|
// Test with existing topic
|
|
|
|
global.compose_state.topic = () => 'one';
|
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.equal(args.opts.trigger, 'narrow_to_compose_target');
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'stream', operand: 'ROME'},
|
|
|
|
{operator: 'topic', operand: 'one'},
|
|
|
|
]);
|
|
|
|
|
|
|
|
// Test with new topic
|
|
|
|
global.compose_state.topic = () => 'four';
|
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'stream', operand: 'ROME'},
|
|
|
|
]);
|
|
|
|
|
|
|
|
// Test with blank topic
|
|
|
|
global.compose_state.topic = () => '';
|
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'stream', operand: 'ROME'},
|
|
|
|
]);
|
|
|
|
|
|
|
|
// Test with no topic
|
|
|
|
global.compose_state.topic = () => {};
|
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'stream', operand: 'ROME'},
|
|
|
|
]);
|
|
|
|
|
|
|
|
// --- Tests for PMs ---
|
|
|
|
global.compose_state.get_message_type = () => 'private';
|
2020-05-26 22:34:15 +02:00
|
|
|
people.add_active_user(ray);
|
|
|
|
people.add_active_user(alice);
|
|
|
|
people.add_active_user(me);
|
2018-11-30 00:20:10 +01:00
|
|
|
|
|
|
|
// Test with valid person
|
2019-12-02 17:53:55 +01:00
|
|
|
global.compose_state.private_message_recipient = () => 'alice@example.com';
|
2018-11-30 00:20:10 +01:00
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'pm-with', operand: 'alice@example.com'},
|
|
|
|
]);
|
|
|
|
|
|
|
|
// Test with valid persons
|
2019-12-02 17:53:55 +01:00
|
|
|
global.compose_state.private_message_recipient = () => 'alice@example.com,ray@example.com';
|
2018-11-30 00:20:10 +01:00
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'pm-with', operand: 'alice@example.com,ray@example.com'},
|
|
|
|
]);
|
|
|
|
|
2020-03-28 01:25:56 +01:00
|
|
|
// Test with some invalid persons
|
2019-12-02 17:53:55 +01:00
|
|
|
global.compose_state.private_message_recipient = () => 'alice@example.com,random,ray@example.com';
|
2018-11-30 00:20:10 +01:00
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'is', operand: 'private'},
|
|
|
|
]);
|
|
|
|
|
2020-03-28 01:25:56 +01:00
|
|
|
// Test with all invalid persons
|
2019-12-02 17:53:55 +01:00
|
|
|
global.compose_state.private_message_recipient = () => 'alice,random,ray';
|
2018-11-30 00:20:10 +01:00
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'is', operand: 'private'},
|
|
|
|
]);
|
|
|
|
|
|
|
|
// Test with no persons
|
2019-12-02 17:53:55 +01:00
|
|
|
global.compose_state.private_message_recipient = () => '';
|
2018-11-30 00:20:10 +01:00
|
|
|
args.called = false;
|
|
|
|
narrow.to_compose_target();
|
|
|
|
assert.equal(args.called, true);
|
|
|
|
assert.deepEqual(args.operators, [
|
|
|
|
{operator: 'is', operand: 'private'},
|
|
|
|
]);
|
|
|
|
|
|
|
|
narrow.activate = activate_backup;
|
|
|
|
});
|