2012-10-18 20:12:04 +02:00
|
|
|
var narrow = (function () {
|
|
|
|
|
|
|
|
var exports = {};
|
|
|
|
|
2014-02-13 18:49:44 +01:00
|
|
|
var unnarrow_times;
|
2012-10-24 00:29:06 +02:00
|
|
|
|
2013-12-06 00:03:08 +01:00
|
|
|
function report_narrow_time(initial_core_time, initial_free_time, network_time) {
|
2013-12-18 19:55:18 +01:00
|
|
|
channel.post({
|
2017-10-16 22:07:19 +02:00
|
|
|
url: '/json/report/narrow_times',
|
2016-12-03 03:08:47 +01:00
|
|
|
data: {initial_core: initial_core_time.toString(),
|
|
|
|
initial_free: initial_free_time.toString(),
|
2017-01-12 00:17:43 +01:00
|
|
|
network: network_time.toString()},
|
2013-12-06 00:03:08 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function maybe_report_narrow_time(msg_list) {
|
|
|
|
if (msg_list.network_time === undefined || msg_list.initial_core_time === undefined ||
|
|
|
|
msg_list.initial_free_time === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
report_narrow_time(msg_list.initial_core_time - msg_list.start_time,
|
|
|
|
msg_list.initial_free_time - msg_list.start_time,
|
|
|
|
msg_list.network_time - msg_list.start_time);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2014-02-13 18:49:44 +01:00
|
|
|
function report_unnarrow_time() {
|
|
|
|
if (unnarrow_times === undefined ||
|
|
|
|
unnarrow_times.start_time === undefined ||
|
|
|
|
unnarrow_times.initial_core_time === undefined ||
|
|
|
|
unnarrow_times.initial_free_time === undefined) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var initial_core_time = unnarrow_times.initial_core_time - unnarrow_times.start_time;
|
|
|
|
var initial_free_time = unnarrow_times.initial_free_time - unnarrow_times.start_time;
|
|
|
|
|
|
|
|
channel.post({
|
2017-10-16 22:07:19 +02:00
|
|
|
url: '/json/report/unnarrow_times',
|
2016-12-03 03:08:47 +01:00
|
|
|
data: {initial_core: initial_core_time.toString(),
|
2017-01-12 00:17:43 +01:00
|
|
|
initial_free: initial_free_time.toString()},
|
2014-02-13 18:49:44 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
unnarrow_times = {};
|
|
|
|
}
|
|
|
|
|
2018-05-03 14:55:01 +02:00
|
|
|
exports.save_pre_narrow_offset_for_reload = function () {
|
|
|
|
if (current_msg_list.selected_id() !== -1) {
|
|
|
|
if (current_msg_list.selected_row().length === 0) {
|
|
|
|
blueslip.debug("narrow.activate missing selected row", {
|
|
|
|
selected_id: current_msg_list.selected_id(),
|
|
|
|
selected_idx: current_msg_list.selected_idx(),
|
2018-05-25 14:37:06 +02:00
|
|
|
selected_idx_exact: current_msg_list.all_messages().indexOf(
|
2018-05-06 21:43:17 +02:00
|
|
|
current_msg_list.get(current_msg_list.selected_id())),
|
2018-05-03 14:55:01 +02:00
|
|
|
render_start: current_msg_list.view._render_win_start,
|
|
|
|
render_end: current_msg_list.view._render_win_end,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
current_msg_list.pre_narrow_offset = current_msg_list.selected_row().offset().top;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2015-12-10 20:37:01 +01:00
|
|
|
exports.narrow_title = "home";
|
2014-01-30 20:54:43 +01:00
|
|
|
exports.activate = function (raw_operators, opts) {
|
2013-12-06 00:03:08 +01:00
|
|
|
var start_time = new Date();
|
2017-04-25 15:25:31 +02:00
|
|
|
var was_narrowed_already = narrow_state.active();
|
2013-10-09 22:42:15 +02:00
|
|
|
// most users aren't going to send a bunch of a out-of-narrow messages
|
|
|
|
// and expect to visit a list of narrows, so let's get these out of the way.
|
|
|
|
notifications.clear_compose_notifications();
|
|
|
|
|
2019-03-06 17:19:00 +01:00
|
|
|
// Open tooltips are only interesting for current narrow,
|
|
|
|
// so hide them when activating a new one.
|
|
|
|
$(".tooltip").hide();
|
|
|
|
|
2014-01-30 20:54:43 +01:00
|
|
|
if (raw_operators.length === 0) {
|
2013-07-19 21:03:46 +02:00
|
|
|
return exports.deactivate();
|
|
|
|
}
|
2014-01-30 20:54:43 +01:00
|
|
|
var filter = new Filter(raw_operators);
|
|
|
|
var operators = filter.operators();
|
|
|
|
|
2015-12-10 20:37:01 +01:00
|
|
|
// Take the most detailed part of the narrow to use as the title.
|
|
|
|
// If the operator is something other than "stream", "topic", or
|
|
|
|
// "is", we shouldn't update the narrow title
|
|
|
|
if (filter.has_operator("stream")) {
|
|
|
|
if (filter.has_operator("topic")) {
|
|
|
|
exports.narrow_title = filter.operands("topic")[0];
|
|
|
|
} else {
|
|
|
|
exports.narrow_title = filter.operands("stream")[0];
|
|
|
|
}
|
|
|
|
} else if (filter.has_operator("is")) {
|
2019-06-18 06:39:49 +02:00
|
|
|
var title = filter.operands("is")[0];
|
|
|
|
title = title.charAt(0).toUpperCase() + title.slice(1) + " messages";
|
|
|
|
exports.narrow_title = title;
|
2018-03-03 17:12:38 +01:00
|
|
|
} else if (filter.has_operator("pm-with") || filter.has_operator("group-pm-with")) {
|
|
|
|
var emails = filter.public_operators()[0].operand;
|
|
|
|
var names = people.get_recipients(people.emails_strings_to_user_ids_string(emails));
|
|
|
|
if (filter.has_operator("pm-with")) {
|
|
|
|
exports.narrow_title = names;
|
|
|
|
} else {
|
|
|
|
exports.narrow_title = names + " and others";
|
|
|
|
}
|
2015-12-10 20:37:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
notifications.redraw_title();
|
2018-10-01 20:27:22 +02:00
|
|
|
notifications.hide_history_limit_message();
|
2014-01-30 20:54:43 +01:00
|
|
|
blueslip.debug("Narrowed", {operators: _.map(operators,
|
|
|
|
function (e) { return e.operator; }),
|
2013-11-05 20:26:03 +01:00
|
|
|
trigger: opts ? opts.trigger : undefined,
|
2014-02-03 22:48:25 +01:00
|
|
|
previous_id: current_msg_list.selected_id()});
|
2013-07-19 21:03:46 +02:00
|
|
|
|
2013-07-30 05:11:50 +02:00
|
|
|
opts = _.defaults({}, opts, {
|
2018-04-23 06:02:11 +02:00
|
|
|
then_select_id: -1,
|
2018-04-23 06:17:56 +02:00
|
|
|
then_select_offset: undefined,
|
2013-05-21 19:34:15 +02:00
|
|
|
change_hash: true,
|
2017-01-12 00:17:43 +01:00
|
|
|
trigger: 'unknown',
|
2013-07-30 05:11:50 +02:00
|
|
|
});
|
2017-08-23 21:43:11 +02:00
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
var id_info = {
|
|
|
|
target_id: undefined,
|
|
|
|
local_select_id: undefined,
|
|
|
|
final_select_id: undefined,
|
|
|
|
};
|
|
|
|
|
2017-08-23 21:43:11 +02:00
|
|
|
// These two narrowing operators specify what message should be
|
|
|
|
// selected and should be the center of the narrow.
|
2013-07-31 20:33:38 +02:00
|
|
|
if (filter.has_operator("near")) {
|
2018-06-01 01:07:45 +02:00
|
|
|
id_info.target_id = parseInt(filter.operands("near")[0], 10);
|
2013-07-31 20:33:38 +02:00
|
|
|
}
|
2013-07-31 20:54:51 +02:00
|
|
|
if (filter.has_operator("id")) {
|
2018-06-01 01:07:45 +02:00
|
|
|
id_info.target_id = parseInt(filter.operands("id")[0], 10);
|
2013-07-31 20:54:51 +02:00
|
|
|
}
|
2012-12-07 20:52:39 +01:00
|
|
|
|
2018-06-01 07:50:17 +02:00
|
|
|
if (opts.then_select_id > 0) {
|
|
|
|
// We override target_id in this case, since the user could be
|
|
|
|
// having a near: narrow auto-reloaded.
|
|
|
|
id_info.target_id = opts.then_select_id;
|
|
|
|
if (opts.then_select_offset === undefined) {
|
|
|
|
var row = current_msg_list.get_row(opts.then_select_id);
|
|
|
|
if (row.length > 0) {
|
|
|
|
opts.then_select_offset = row.offset().top;
|
|
|
|
}
|
2018-05-13 14:31:44 +02:00
|
|
|
}
|
2018-06-01 07:50:17 +02:00
|
|
|
}
|
2018-05-13 14:31:44 +02:00
|
|
|
|
2013-11-26 19:06:21 +01:00
|
|
|
if (!was_narrowed_already) {
|
2016-04-03 16:45:07 +02:00
|
|
|
unread.messages_read_in_narrow = false;
|
2013-11-26 19:06:21 +01:00
|
|
|
}
|
|
|
|
|
2018-05-03 15:05:57 +02:00
|
|
|
// IMPORTANT! At this point we are heavily committed to
|
|
|
|
// populating the new narrow, so we update our narrow_state.
|
|
|
|
// From here on down, any calls to the narrow_state API will
|
|
|
|
// reflect the upcoming narrow.
|
2017-04-25 15:25:31 +02:00
|
|
|
narrow_state.set_current_filter(filter);
|
2018-05-03 15:05:57 +02:00
|
|
|
|
2017-04-25 15:25:31 +02:00
|
|
|
var muting_enabled = narrow_state.muting_enabled();
|
2012-12-12 19:00:50 +01:00
|
|
|
|
2013-07-03 21:39:41 +02:00
|
|
|
// Save how far from the pointer the top of the message list was.
|
2018-05-03 14:55:01 +02:00
|
|
|
exports.save_pre_narrow_offset_for_reload();
|
2013-07-25 22:08:16 +02:00
|
|
|
|
2018-05-14 17:47:14 +02:00
|
|
|
var msg_data = new MessageListData({
|
2018-07-07 15:55:39 +02:00
|
|
|
filter: narrow_state.filter(),
|
2018-05-14 17:47:14 +02:00
|
|
|
muting_enabled: muting_enabled,
|
|
|
|
});
|
|
|
|
|
2018-05-14 19:57:46 +02:00
|
|
|
// Populate the message list if we can apply our filter locally (i.e.
|
|
|
|
// with no backend help) and we have the message we want to select.
|
2018-06-01 01:07:45 +02:00
|
|
|
// Also update id_info accordingly.
|
2018-05-31 17:21:00 +02:00
|
|
|
// original back.
|
2018-06-01 01:07:45 +02:00
|
|
|
exports.maybe_add_local_messages({
|
|
|
|
id_info: id_info,
|
2018-05-31 17:21:00 +02:00
|
|
|
msg_data: msg_data,
|
|
|
|
});
|
2018-05-14 19:57:46 +02:00
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
if (!id_info.local_select_id) {
|
|
|
|
// If we're not actually read to select an ID, we need to
|
|
|
|
// trash the `MessageListData` object that we just constructed
|
|
|
|
// and pass an empty one to MessageList, because the block of
|
|
|
|
// messages in the MessageListData built inside
|
|
|
|
// maybe_add_local_messages is likely not be contiguous with
|
|
|
|
// the block we're about to request from the server instead.
|
|
|
|
msg_data = new MessageListData({
|
2018-07-07 15:55:39 +02:00
|
|
|
filter: narrow_state.filter(),
|
2018-06-01 01:07:45 +02:00
|
|
|
muting_enabled: muting_enabled,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-05-14 15:46:25 +02:00
|
|
|
var msg_list = new message_list.MessageList({
|
2018-05-14 17:47:14 +02:00
|
|
|
data: msg_data,
|
2018-05-14 15:46:25 +02:00
|
|
|
table_name: 'zfilt',
|
2018-07-07 15:55:39 +02:00
|
|
|
collapse_messages: !narrow_state.filter().is_search(),
|
2018-05-14 15:46:25 +02:00
|
|
|
});
|
2017-04-25 15:25:31 +02:00
|
|
|
|
2013-12-06 00:03:08 +01:00
|
|
|
msg_list.start_time = start_time;
|
2013-07-03 21:39:41 +02:00
|
|
|
|
2013-12-09 19:20:55 +01:00
|
|
|
// Show the new set of messages. It is important to set current_msg_list to
|
|
|
|
// the view right as it's being shown, because we rely on current_msg_list
|
|
|
|
// being shown for deciding when to condense messages.
|
|
|
|
$("body").addClass("narrowed_view");
|
|
|
|
$("#zfilt").addClass("focused_table");
|
|
|
|
$("#zhome").removeClass("focused_table");
|
2016-06-18 19:34:20 +02:00
|
|
|
|
2017-03-18 21:35:35 +01:00
|
|
|
ui_util.change_tab_to('#home');
|
2016-04-25 23:45:25 +02:00
|
|
|
message_list.narrowed = msg_list;
|
|
|
|
current_msg_list = message_list.narrowed;
|
2013-02-12 20:01:24 +01:00
|
|
|
|
2018-06-01 07:50:17 +02:00
|
|
|
var then_select_offset;
|
|
|
|
if (id_info.target_id === id_info.final_select_id) {
|
|
|
|
then_select_offset = opts.then_select_offset;
|
|
|
|
}
|
2018-05-13 14:31:44 +02:00
|
|
|
|
2018-06-06 18:19:09 +02:00
|
|
|
var select_immediately = id_info.local_select_id !== undefined;
|
2018-05-03 14:09:37 +02:00
|
|
|
|
2018-05-03 03:53:26 +02:00
|
|
|
(function fetch_messages() {
|
|
|
|
var anchor;
|
|
|
|
var use_first_unread;
|
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
if (id_info.final_select_id !== undefined) {
|
|
|
|
anchor = id_info.final_select_id;
|
2018-05-03 03:53:26 +02:00
|
|
|
use_first_unread = false;
|
2018-06-01 01:07:45 +02:00
|
|
|
} else {
|
2018-05-03 03:53:26 +02:00
|
|
|
anchor = -1;
|
|
|
|
use_first_unread = true;
|
|
|
|
}
|
|
|
|
|
2018-05-03 14:09:37 +02:00
|
|
|
message_fetch.load_messages_for_narrow({
|
2018-05-03 03:53:26 +02:00
|
|
|
then_select_id: anchor,
|
|
|
|
use_first_unread_anchor: use_first_unread,
|
2018-05-03 14:09:37 +02:00
|
|
|
cont: function () {
|
2018-05-04 17:44:17 +02:00
|
|
|
if (!select_immediately) {
|
2018-05-03 14:34:29 +02:00
|
|
|
exports.update_selection({
|
2018-06-01 01:07:45 +02:00
|
|
|
id_info: id_info,
|
2018-05-03 14:34:29 +02:00
|
|
|
select_offset: then_select_offset,
|
|
|
|
});
|
2018-05-03 14:09:37 +02:00
|
|
|
}
|
|
|
|
msg_list.network_time = new Date();
|
|
|
|
maybe_report_narrow_time(msg_list);
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}());
|
2013-02-20 19:35:15 +01:00
|
|
|
|
2018-05-04 17:44:17 +02:00
|
|
|
if (select_immediately) {
|
2018-03-09 22:12:38 +01:00
|
|
|
message_scroll.hide_indicators();
|
2018-05-03 14:34:29 +02:00
|
|
|
exports.update_selection({
|
2018-06-01 01:07:45 +02:00
|
|
|
id_info: id_info,
|
2018-05-03 14:34:29 +02:00
|
|
|
select_offset: then_select_offset,
|
|
|
|
});
|
2014-01-22 22:20:36 +01:00
|
|
|
} else {
|
2018-03-09 14:27:42 +01:00
|
|
|
message_scroll.show_loading_older();
|
2013-04-10 17:55:02 +02:00
|
|
|
}
|
2012-10-26 16:59:38 +02:00
|
|
|
|
2013-03-19 23:45:51 +01:00
|
|
|
// Put the narrow operators in the URL fragment.
|
|
|
|
// Disabled when the URL fragment was the source
|
|
|
|
// of this narrow.
|
2013-08-01 17:47:48 +02:00
|
|
|
if (opts.change_hash) {
|
2013-03-19 23:45:51 +01:00
|
|
|
hashchange.save_narrow(operators);
|
2013-08-01 17:47:48 +02:00
|
|
|
}
|
2013-03-19 23:45:51 +01:00
|
|
|
|
2018-07-14 16:10:00 +02:00
|
|
|
if (page_params.search_pills_enabled && opts.trigger !== 'search') {
|
2018-07-23 02:20:57 +02:00
|
|
|
search_pill_widget.widget.clear(true);
|
2018-07-14 16:10:00 +02:00
|
|
|
_.each(operators, function (operator) {
|
|
|
|
var search_string = Filter.unparse([operator]);
|
2018-07-23 02:20:57 +02:00
|
|
|
search_pill.append_search_string(search_string, search_pill_widget.widget);
|
2018-07-14 16:10:00 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-08-09 05:59:55 +02:00
|
|
|
if (filter.has_operator("is") && filter.operands("is")[0] === "private"
|
|
|
|
|| filter.has_operator("pm-with") || filter.has_operator("group-pm-with")) {
|
2019-03-06 23:46:53 +01:00
|
|
|
compose.update_closed_compose_buttons_for_private();
|
2018-08-09 05:59:55 +02:00
|
|
|
} else {
|
2019-03-06 23:46:53 +01:00
|
|
|
compose.update_closed_compose_buttons_for_stream();
|
2018-08-09 05:59:55 +02:00
|
|
|
}
|
|
|
|
|
2013-03-19 23:45:51 +01:00
|
|
|
// Put the narrow operators in the search bar.
|
2013-08-22 01:29:28 +02:00
|
|
|
$('#search_query').val(Filter.unparse(operators));
|
2012-12-18 23:38:55 +01:00
|
|
|
search.update_button_visibility();
|
2013-10-10 15:54:18 +02:00
|
|
|
|
2018-02-16 15:56:25 +01:00
|
|
|
compose_actions.on_narrow(opts);
|
2013-10-10 15:54:18 +02:00
|
|
|
|
2018-07-07 15:55:39 +02:00
|
|
|
var current_filter = narrow_state.filter();
|
2017-08-12 16:49:10 +02:00
|
|
|
|
2017-08-12 17:26:12 +02:00
|
|
|
top_left_corner.handle_narrow_activated(current_filter);
|
2017-08-12 16:49:10 +02:00
|
|
|
stream_list.handle_narrow_activated(current_filter);
|
2018-08-06 18:09:51 +02:00
|
|
|
typing_events.render_notifications_for_narrow();
|
2018-08-06 18:12:20 +02:00
|
|
|
tab_bar.initialize();
|
2017-08-12 16:49:10 +02:00
|
|
|
|
2013-12-06 00:03:08 +01:00
|
|
|
msg_list.initial_core_time = new Date();
|
|
|
|
setTimeout(function () {
|
|
|
|
msg_list.initial_free_time = new Date();
|
|
|
|
maybe_report_narrow_time(msg_list);
|
|
|
|
}, 0);
|
2012-12-12 19:00:50 +01:00
|
|
|
};
|
2012-10-03 20:49:58 +02:00
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
function min_defined(a, b) {
|
|
|
|
if (a === undefined) {
|
|
|
|
return b;
|
|
|
|
}
|
|
|
|
if (b === undefined) {
|
|
|
|
return a;
|
|
|
|
}
|
|
|
|
return a < b ? a : b;
|
|
|
|
}
|
|
|
|
|
2018-05-14 19:57:46 +02:00
|
|
|
function load_local_messages(msg_data) {
|
2018-05-04 17:44:17 +02:00
|
|
|
// This little helper loads messages into our narrow message
|
2018-05-14 19:57:46 +02:00
|
|
|
// data and returns true unless it's empty. We use this for
|
2018-05-04 17:44:17 +02:00
|
|
|
// cases when our local cache (message_list.all) has at least
|
|
|
|
// one message the user will expect to see in the new narrow.
|
|
|
|
|
2018-05-14 19:57:46 +02:00
|
|
|
var in_msgs = message_list.all.all_messages();
|
|
|
|
msg_data.add_messages(in_msgs);
|
|
|
|
|
|
|
|
return !msg_data.empty();
|
2018-05-04 17:44:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
exports.maybe_add_local_messages = function (opts) {
|
|
|
|
// This function does two very closely related things, both of
|
|
|
|
// which are somewhat optional:
|
|
|
|
//
|
2018-06-01 01:07:45 +02:00
|
|
|
// - update id_info with more complete values
|
2018-05-04 17:44:17 +02:00
|
|
|
// - add messages into our message list from our local cache
|
2018-06-01 01:07:45 +02:00
|
|
|
var id_info = opts.id_info;
|
2018-05-14 19:57:46 +02:00
|
|
|
var msg_data = opts.msg_data;
|
2018-06-01 01:07:45 +02:00
|
|
|
var unread_info = narrow_state.get_first_unread_info();
|
|
|
|
|
|
|
|
if (unread_info.flavor === 'cannot_compute') {
|
|
|
|
if (id_info.target_id) {
|
|
|
|
// TODO: Ideally, in this case we should be asking the
|
|
|
|
// server to give us the first unread or the target_id,
|
|
|
|
// whichever is first (i.e. basically the `found` logic
|
|
|
|
// below), but the server doesn't support that query.
|
|
|
|
id_info.final_select_id = id_info.target_id;
|
|
|
|
}
|
|
|
|
// if we can't compute a next unread id, just return without
|
|
|
|
// setting local_select_id, so that we go to the server.
|
|
|
|
return;
|
|
|
|
}
|
2018-05-04 17:44:17 +02:00
|
|
|
|
2018-07-07 15:55:39 +02:00
|
|
|
// We can now assume narrow_state.filter().can_apply_locally(),
|
2018-06-01 01:07:45 +02:00
|
|
|
// because !can_apply_locally => cannot_compute
|
|
|
|
|
|
|
|
if (unread_info.flavor === 'found') {
|
|
|
|
// We have at least one unread message in this narrow. So
|
|
|
|
// either we aim for the first unread message, or the
|
|
|
|
// target_id (if any), whichever is earlier. See #2091 for a
|
|
|
|
// detailed explanation of why we need to look at unread here.
|
|
|
|
id_info.final_select_id = min_defined(
|
|
|
|
id_info.target_id,
|
|
|
|
unread_info.msg_id
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!load_local_messages(msg_data)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now that we know what message ID we're going to land on, we
|
|
|
|
// can see if we can take the user there locally.
|
|
|
|
if (msg_data.get(id_info.final_select_id)) {
|
|
|
|
id_info.local_select_id = id_info.final_select_id;
|
2018-05-04 17:44:17 +02:00
|
|
|
}
|
2018-06-01 01:07:45 +02:00
|
|
|
|
|
|
|
// If we don't have the first unread message locally, we must
|
|
|
|
// go to the server to get it before we can render the narrow.
|
|
|
|
return;
|
2018-05-04 17:44:17 +02:00
|
|
|
}
|
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
// Now we know that there are no unread messages, because
|
|
|
|
// unread_info.flavor === 'not_found'
|
|
|
|
|
|
|
|
if (!id_info.target_id) {
|
|
|
|
// Without unread messages or a target ID, we're narrowing to
|
|
|
|
// the very latest message matching the narrow.
|
|
|
|
|
|
|
|
// TODO: A possible optimization in this code path is to set
|
|
|
|
// `id_info.final_select_id` to be `max_int` here, i.e. saving the
|
|
|
|
// server the first_unread query when we need the server.
|
|
|
|
if (!message_list.all.fetch_status.has_found_newest()) {
|
|
|
|
// If message_list.all is not caught up, then we cannot
|
|
|
|
// populate the latest messages for the target narrow
|
|
|
|
// correctly from there, so we must go to the server.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!load_local_messages(msg_data)) {
|
|
|
|
return;
|
2018-05-04 17:44:17 +02:00
|
|
|
}
|
2018-06-01 01:07:45 +02:00
|
|
|
// Otherwise, we have matching messages, and message_list.all
|
|
|
|
// is caught up, so the last message in our now-populated
|
|
|
|
// msg_data object must be the last message matching the
|
|
|
|
// narrow the server could give us, so we can render locally.
|
|
|
|
var last_msg = msg_data.last();
|
|
|
|
id_info.final_select_id = last_msg.id;
|
|
|
|
id_info.local_select_id = id_info.final_select_id;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have a target_id and no unread messages complicating things,
|
|
|
|
// so we definitely want to land on the target_id message.
|
|
|
|
id_info.final_select_id = id_info.target_id;
|
2018-05-05 02:25:46 +02:00
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
if (message_list.all.empty() ||
|
|
|
|
id_info.target_id < message_list.all.first().id ||
|
|
|
|
id_info.target_id > message_list.all.last().id) {
|
|
|
|
// If the target message is outside the range that we had
|
|
|
|
// available for local population, we must go to the server.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!load_local_messages(msg_data)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (msg_data.get(id_info.target_id)) {
|
|
|
|
// We have a range of locally renderable messages, including
|
|
|
|
// our target, so we can render the narrow locally.
|
|
|
|
id_info.local_select_id = id_info.final_select_id;
|
|
|
|
return;
|
2018-05-04 17:44:17 +02:00
|
|
|
}
|
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
// Note: Arguably, we could have a use_closest sort of condition
|
|
|
|
// here to handle cases where `target_id` doesn't match the narrow
|
|
|
|
// but is within the locally renderable range. But
|
|
|
|
// !can_apply_locally + target_id is a rare combination in the
|
|
|
|
// first place, so we don't bother.
|
|
|
|
return;
|
2018-05-04 17:44:17 +02:00
|
|
|
};
|
|
|
|
|
2018-05-03 14:34:29 +02:00
|
|
|
exports.update_selection = function (opts) {
|
|
|
|
if (message_list.narrowed.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
var id_info = opts.id_info;
|
2018-05-03 14:34:29 +02:00
|
|
|
var select_offset = opts.select_offset;
|
|
|
|
|
2018-06-01 01:07:45 +02:00
|
|
|
var msg_id = id_info.final_select_id;
|
|
|
|
if (msg_id === undefined) {
|
2018-05-03 14:34:29 +02:00
|
|
|
msg_id = message_list.narrowed.first_unread_message_id();
|
|
|
|
}
|
|
|
|
|
|
|
|
var preserve_pre_narrowing_screen_position =
|
2018-06-06 18:50:09 +02:00
|
|
|
message_list.narrowed.get(msg_id) !== undefined &&
|
|
|
|
select_offset !== undefined;
|
2018-05-03 14:34:29 +02:00
|
|
|
|
|
|
|
var then_scroll = !preserve_pre_narrowing_screen_position;
|
|
|
|
|
2018-05-06 21:43:17 +02:00
|
|
|
message_list.narrowed.select_id(msg_id, {
|
|
|
|
then_scroll: then_scroll,
|
|
|
|
use_closest: true,
|
|
|
|
force_rerender: true,
|
|
|
|
});
|
2018-05-03 14:34:29 +02:00
|
|
|
|
|
|
|
if (preserve_pre_narrowing_screen_position) {
|
|
|
|
// Scroll so that the selected message is in the same
|
|
|
|
// position in the viewport as it was prior to
|
|
|
|
// narrowing
|
|
|
|
message_list.narrowed.view.set_message_offset(select_offset);
|
|
|
|
}
|
|
|
|
unread_ops.process_visible();
|
|
|
|
};
|
|
|
|
|
2017-04-21 21:33:06 +02:00
|
|
|
exports.stream_topic = function () {
|
|
|
|
// This function returns the stream/topic that we most
|
|
|
|
// specifically care about, according (mostly) to the
|
|
|
|
// currently selected message.
|
|
|
|
var msg = current_msg_list.selected_message();
|
|
|
|
|
|
|
|
if (msg) {
|
|
|
|
return {
|
|
|
|
stream: msg.stream || undefined,
|
2018-12-22 18:54:37 +01:00
|
|
|
topic: util.get_message_topic(msg) || undefined,
|
2017-04-21 21:33:06 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
// We may be in an empty narrow. In that case we use
|
|
|
|
// our narrow parameters to return the stream/topic.
|
|
|
|
return {
|
2017-04-25 15:25:31 +02:00
|
|
|
stream: narrow_state.stream(),
|
|
|
|
topic: narrow_state.topic(),
|
2017-04-21 21:33:06 +02:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2017-08-16 19:06:07 +02:00
|
|
|
exports.activate_stream_for_cycle_hotkey = function (stream_name) {
|
|
|
|
// This is the common code for A/D hotkeys.
|
|
|
|
var filter_expr = [
|
|
|
|
{operator: 'stream', operand: stream_name},
|
|
|
|
];
|
2018-04-23 06:02:11 +02:00
|
|
|
exports.activate(filter_expr, {});
|
2017-08-16 19:06:07 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
exports.stream_cycle_backward = function () {
|
|
|
|
var curr_stream = narrow_state.stream();
|
|
|
|
|
|
|
|
if (!curr_stream) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var stream_name = topic_generator.get_prev_stream(curr_stream);
|
|
|
|
|
|
|
|
if (!stream_name) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.activate_stream_for_cycle_hotkey(stream_name);
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.stream_cycle_forward = function () {
|
|
|
|
var curr_stream = narrow_state.stream();
|
|
|
|
|
|
|
|
if (!curr_stream) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var stream_name = topic_generator.get_next_stream(curr_stream);
|
|
|
|
|
|
|
|
if (!stream_name) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.activate_stream_for_cycle_hotkey(stream_name);
|
|
|
|
};
|
|
|
|
|
2017-04-21 23:49:33 +02:00
|
|
|
exports.narrow_to_next_topic = function () {
|
|
|
|
var curr_info = exports.stream_topic();
|
|
|
|
|
2017-05-31 21:42:52 +02:00
|
|
|
if (!curr_info) {
|
2017-04-21 23:49:33 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var next_narrow = topic_generator.get_next_topic(
|
|
|
|
curr_info.stream,
|
|
|
|
curr_info.topic
|
|
|
|
);
|
|
|
|
|
|
|
|
if (!next_narrow) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var filter_expr = [
|
|
|
|
{operator: 'stream', operand: next_narrow.stream},
|
|
|
|
{operator: 'topic', operand: next_narrow.topic},
|
|
|
|
];
|
|
|
|
|
2018-04-23 06:02:11 +02:00
|
|
|
exports.activate(filter_expr, {});
|
2017-04-21 23:49:33 +02:00
|
|
|
};
|
|
|
|
|
2018-02-09 23:04:20 +01:00
|
|
|
exports.narrow_to_next_pm_string = function () {
|
2018-02-16 15:56:25 +01:00
|
|
|
|
2018-02-09 23:04:20 +01:00
|
|
|
var curr_pm = narrow_state.pm_string();
|
|
|
|
|
|
|
|
var next_pm = topic_generator.get_next_unread_pm_string(curr_pm);
|
|
|
|
|
|
|
|
if (!next_pm) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hopefully someday we can narrow by user_ids_string instead of
|
|
|
|
// mapping back to emails.
|
|
|
|
var pm_with = people.user_ids_string_to_emails_string(next_pm);
|
|
|
|
|
|
|
|
var filter_expr = [
|
|
|
|
{operator: 'pm-with', operand: pm_with},
|
|
|
|
];
|
|
|
|
|
2018-02-16 15:56:25 +01:00
|
|
|
// force_close parameter is true to not auto open compose_box
|
2018-02-09 23:04:20 +01:00
|
|
|
var opts = {
|
2018-02-16 15:56:25 +01:00
|
|
|
force_close: true,
|
2018-02-09 23:04:20 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.activate(filter_expr, opts);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-01-02 19:21:39 +01:00
|
|
|
// Activate narrowing with a single operator.
|
|
|
|
// This is just for syntactic convenience.
|
|
|
|
exports.by = function (operator, operand, opts) {
|
2014-02-10 20:53:38 +01:00
|
|
|
exports.activate([{operator: operator, operand: operand}], opts);
|
2013-02-09 08:27:20 +01:00
|
|
|
};
|
|
|
|
|
2018-11-13 16:13:41 +01:00
|
|
|
exports.by_topic = function (target_id, opts) {
|
2013-10-09 22:42:15 +02:00
|
|
|
// don't use current_msg_list as it won't work for muted messages or for out-of-narrow links
|
2014-01-31 22:02:57 +01:00
|
|
|
var original = message_store.get(target_id);
|
2012-10-24 05:04:42 +02:00
|
|
|
if (original.type !== 'stream') {
|
2016-10-28 19:07:25 +02:00
|
|
|
// Only stream messages have topics, but the
|
2012-10-24 05:04:42 +02:00
|
|
|
// user wants us to narrow in some way.
|
2013-05-21 19:34:15 +02:00
|
|
|
exports.by_recipient(target_id, opts);
|
2012-10-03 20:49:58 +02:00
|
|
|
return;
|
2012-10-24 05:04:42 +02:00
|
|
|
}
|
2018-04-04 21:32:45 +02:00
|
|
|
unread_ops.notify_server_message_read(original);
|
2014-02-10 20:53:38 +01:00
|
|
|
var search_terms = [
|
|
|
|
{operator: 'stream', operand: original.stream},
|
2018-12-22 18:54:37 +01:00
|
|
|
{operator: 'topic', operand: util.get_message_topic(original)},
|
2014-02-10 20:53:38 +01:00
|
|
|
];
|
2013-07-30 05:11:50 +02:00
|
|
|
opts = _.defaults({}, opts, {then_select_id: target_id});
|
2014-02-10 20:53:38 +01:00
|
|
|
exports.activate(search_terms, opts);
|
2012-11-15 16:57:59 +01:00
|
|
|
};
|
|
|
|
|
2012-10-10 23:24:11 +02:00
|
|
|
// Called for the 'narrow by stream' hotkey.
|
2013-05-21 19:34:15 +02:00
|
|
|
exports.by_recipient = function (target_id, opts) {
|
2013-07-30 05:11:50 +02:00
|
|
|
opts = _.defaults({}, opts, {then_select_id: target_id});
|
2013-10-09 22:42:15 +02:00
|
|
|
// don't use current_msg_list as it won't work for muted messages or for out-of-narrow links
|
2014-01-31 22:02:57 +01:00
|
|
|
var message = message_store.get(target_id);
|
2018-04-04 21:32:45 +02:00
|
|
|
unread_ops.notify_server_message_read(message);
|
2012-10-19 19:00:46 +02:00
|
|
|
switch (message.type) {
|
2012-12-03 19:49:12 +01:00
|
|
|
case 'private':
|
2013-05-21 19:34:15 +02:00
|
|
|
exports.by('pm-with', message.reply_to, opts);
|
2012-10-19 17:11:31 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 'stream':
|
2013-05-21 19:34:15 +02:00
|
|
|
exports.by('stream', message.stream, opts);
|
2012-10-19 17:11:31 +02:00
|
|
|
break;
|
2012-10-03 20:49:58 +02:00
|
|
|
}
|
2012-10-18 20:12:04 +02:00
|
|
|
};
|
2012-10-03 20:49:58 +02:00
|
|
|
|
2018-11-30 00:20:10 +01:00
|
|
|
// Called by the narrow_to_compose_target hotkey.
|
|
|
|
exports.to_compose_target = function () {
|
|
|
|
if (!compose_state.composing()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
var opts = {
|
|
|
|
trigger: 'narrow_to_compose_target',
|
|
|
|
};
|
|
|
|
|
|
|
|
if (compose_state.get_message_type() === 'stream') {
|
|
|
|
var stream_name = compose_state.stream_name();
|
|
|
|
var stream_id = stream_data.get_stream_id(stream_name);
|
|
|
|
if (!stream_id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// If we are composing to a new topic, we narrow to the stream but
|
|
|
|
// grey-out the message view instead of narrowing to an empty view.
|
|
|
|
var topics = topic_data.get_recent_names(stream_id);
|
|
|
|
var operators = [{operator: 'stream', operand: stream_name}];
|
|
|
|
var topic = compose_state.topic();
|
|
|
|
if (topics.indexOf(topic) !== -1) {
|
|
|
|
operators.push({operator: 'topic', operand: topic});
|
|
|
|
}
|
|
|
|
exports.activate(operators, opts);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compose_state.get_message_type() === 'private') {
|
|
|
|
var recipient_string = compose_state.recipient();
|
|
|
|
var emails = util.extract_pm_recipients(recipient_string);
|
|
|
|
var invalid = _.reject(emails, people.is_valid_email_for_compose);
|
|
|
|
// If there are no recipients or any recipient is
|
|
|
|
// invalid, narrow to all PMs.
|
|
|
|
if (emails.length === 0 || invalid.length > 0) {
|
|
|
|
exports.by('is', 'private', opts);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
exports.by('pm-with', util.normalize_recipients(recipient_string), opts);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-08-06 17:43:24 +02:00
|
|
|
function handle_post_narrow_deactivate_processes() {
|
|
|
|
compose_fade.update_message_list();
|
|
|
|
|
|
|
|
// clear existing search pills
|
|
|
|
if (page_params.search_pills_enabled) {
|
|
|
|
search_pill_widget.widget.clear(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
top_left_corner.handle_narrow_deactivated();
|
|
|
|
stream_list.handle_narrow_deactivated();
|
2019-03-06 23:46:53 +01:00
|
|
|
compose.update_closed_compose_buttons_for_stream();
|
2018-08-06 18:01:04 +02:00
|
|
|
message_edit.handle_narrow_deactivated();
|
|
|
|
widgetize.set_widgets_for_list();
|
2018-08-06 18:09:51 +02:00
|
|
|
typing_events.render_notifications_for_narrow();
|
2018-08-06 18:12:20 +02:00
|
|
|
tab_bar.initialize();
|
2018-08-06 17:43:24 +02:00
|
|
|
exports.narrow_title = "home";
|
|
|
|
notifications.redraw_title();
|
2018-10-01 20:27:22 +02:00
|
|
|
notifications.hide_or_show_history_limit_message(home_msg_list);
|
2018-08-06 17:43:24 +02:00
|
|
|
}
|
|
|
|
|
2012-12-12 20:36:05 +01:00
|
|
|
exports.deactivate = function () {
|
Simplify narrow/search interactions.
Before this change, if you hit ESC, then hotkey
code would call search.clear_search, which would
call narrow.deactivate(), which would then use
`$('#search_query')` to clear a value, but then
let search.clear_search blur the input and
disable the exit button. It was all confusing.
Things are a bit more organized now.
Now the code works like this:
hotkey.process_escape_key
Just call narrow.deactivate.
$('#search_exit').on('click', ...):
Just call narrow.deactivate.
narrow.deactivate:
Just call search.clear_search_form
search.clear_search_form:
Just do simple jquery stuff. Don't
change the entire user's narrow, not
even indirectly!
There's still a two-way interaction between
the narrow.js module and the search.js module,
but in each direction it's a one-liner.
The guiding principle here is that we only
want one top-level API, which is narrow.deactivate,
and that does the whole "kitchen sink" of
clearing searches, closing popovers, switching
in views, etc. And then all the functions it
calls out to tend to have much smaller jobs to
do.
This commit can mostly be considered a refactoring, but the
order of operations changes slightly. Basically, as
soon as you hit ESC or click on the search "X", we
clear the search widget. Most users won't notice
any difference, because we don't have to hit the
server to populate the home view. And it's arguably
an improvement to give more immediate feedback.
2018-09-10 19:36:58 +02:00
|
|
|
search.clear_search_form();
|
2018-07-07 15:55:39 +02:00
|
|
|
if (narrow_state.filter() === undefined) {
|
2012-10-03 20:49:58 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-02-13 18:49:44 +01:00
|
|
|
unnarrow_times = {start_time: new Date()};
|
2013-10-30 18:38:16 +01:00
|
|
|
blueslip.debug("Unnarrowed");
|
2013-04-24 21:40:08 +02:00
|
|
|
|
2018-03-08 20:18:36 +01:00
|
|
|
if (message_scroll.actively_scrolling()) {
|
2013-07-16 20:00:47 +02:00
|
|
|
// There is no way to intercept in-flight scroll events, and they will
|
|
|
|
// cause you to end up in the wrong place if you are actively scrolling
|
|
|
|
// on an unnarrow. Wait a bit and try again once the scrolling is over.
|
|
|
|
setTimeout(exports.deactivate, 50);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-03-18 18:10:37 +01:00
|
|
|
if (!compose_state.has_message_content()) {
|
2017-03-18 17:55:11 +01:00
|
|
|
compose_actions.cancel();
|
2013-10-10 16:43:49 +02:00
|
|
|
}
|
2013-10-10 15:08:17 +02:00
|
|
|
|
2017-04-25 15:25:31 +02:00
|
|
|
narrow_state.reset_current_filter();
|
2012-10-03 20:49:58 +02:00
|
|
|
|
2013-03-29 19:55:28 +01:00
|
|
|
exports.hide_empty_narrow_message();
|
2013-02-23 19:38:25 +01:00
|
|
|
|
2013-07-17 00:52:18 +02:00
|
|
|
$("body").removeClass('narrowed_view');
|
2013-01-09 23:22:21 +01:00
|
|
|
$("#zfilt").removeClass('focused_table');
|
|
|
|
$("#zhome").addClass('focused_table');
|
2013-12-09 19:20:55 +01:00
|
|
|
current_msg_list = home_msg_list;
|
2018-03-27 18:52:45 +02:00
|
|
|
condense.condense_and_collapse($("#zhome div.message_row"));
|
2013-01-09 23:46:32 +01:00
|
|
|
|
2018-03-09 22:12:38 +01:00
|
|
|
message_scroll.hide_indicators();
|
2014-01-15 17:48:40 +01:00
|
|
|
hashchange.save_narrow();
|
2013-02-14 23:48:37 +01:00
|
|
|
|
2013-12-02 19:16:37 +01:00
|
|
|
if (current_msg_list.selected_id() !== -1) {
|
|
|
|
var preserve_pre_narrowing_screen_position =
|
2018-06-06 18:50:09 +02:00
|
|
|
current_msg_list.selected_row().length > 0 &&
|
|
|
|
current_msg_list.pre_narrow_offset !== undefined;
|
2014-02-04 22:13:34 +01:00
|
|
|
var message_id_to_select;
|
|
|
|
var select_opts = {
|
|
|
|
then_scroll: true,
|
|
|
|
use_closest: true,
|
2017-01-12 00:17:43 +01:00
|
|
|
empty_ok: true,
|
2014-02-04 22:13:34 +01:00
|
|
|
};
|
2013-12-02 19:16:37 +01:00
|
|
|
|
2014-02-04 22:13:34 +01:00
|
|
|
// We fall back to the closest selected id, if the user has removed a
|
|
|
|
// stream from the home view since leaving it the old selected id might
|
|
|
|
// no longer be there
|
|
|
|
// Additionally, we pass empty_ok as the user may have removed **all** streams
|
2017-07-05 11:43:14 +02:00
|
|
|
// from their home view
|
2016-04-03 16:45:07 +02:00
|
|
|
if (unread.messages_read_in_narrow) {
|
2013-11-26 19:06:21 +01:00
|
|
|
// We read some unread messages in a narrow. Instead of going back to
|
|
|
|
// where we were before the narrow, go to our first unread message (or
|
|
|
|
// the bottom of the feed, if there are no unread messages).
|
2017-08-02 22:37:13 +02:00
|
|
|
message_id_to_select = current_msg_list.first_unread_message_id();
|
2013-11-26 19:06:21 +01:00
|
|
|
} else {
|
|
|
|
// We narrowed, but only backwards in time (ie no unread were read). Try
|
|
|
|
// to go back to exactly where we were before narrowing.
|
2014-01-09 22:57:53 +01:00
|
|
|
if (preserve_pre_narrowing_screen_position) {
|
|
|
|
// We scroll the user back to exactly the offset from the selected
|
2017-07-05 11:43:14 +02:00
|
|
|
// message that they were at the time that they narrowed.
|
2014-01-09 22:57:53 +01:00
|
|
|
// TODO: Make this correctly handle the case of resizing while narrowed.
|
2014-02-04 22:13:34 +01:00
|
|
|
select_opts.target_scroll_offset = current_msg_list.pre_narrow_offset;
|
2014-01-09 22:57:53 +01:00
|
|
|
}
|
2014-02-04 22:13:34 +01:00
|
|
|
message_id_to_select = current_msg_list.selected_id();
|
2013-12-02 19:16:37 +01:00
|
|
|
}
|
2014-02-04 22:13:34 +01:00
|
|
|
current_msg_list.select_id(message_id_to_select, select_opts);
|
2013-07-03 21:39:41 +02:00
|
|
|
}
|
2013-01-11 16:57:17 +01:00
|
|
|
|
2018-08-06 17:43:24 +02:00
|
|
|
handle_post_narrow_deactivate_processes();
|
2015-12-10 20:37:01 +01:00
|
|
|
|
2014-02-13 18:49:44 +01:00
|
|
|
unnarrow_times.initial_core_time = new Date();
|
|
|
|
setTimeout(function () {
|
|
|
|
unnarrow_times.initial_free_time = new Date();
|
|
|
|
report_unnarrow_time();
|
|
|
|
});
|
2012-10-18 20:12:04 +02:00
|
|
|
};
|
|
|
|
|
2013-07-05 17:43:56 +02:00
|
|
|
exports.restore_home_state = function () {
|
2017-08-08 07:37:39 +02:00
|
|
|
// If we click on the All Messages link while already at All Messages, unnarrow.
|
|
|
|
// If we click on the All Messages link from another nav pane, just go
|
2012-11-04 02:16:15 +01:00
|
|
|
// back to the state you were in (possibly still narrowed) before
|
2017-08-08 07:37:39 +02:00
|
|
|
// you left the All Messages pane.
|
2017-05-27 15:40:54 +02:00
|
|
|
if (!overlays.is_active()) {
|
2012-12-12 20:36:05 +01:00
|
|
|
exports.deactivate();
|
2012-11-04 02:16:15 +01:00
|
|
|
}
|
2016-05-25 13:24:33 +02:00
|
|
|
navigate.maybe_scroll_to_selected();
|
2012-11-04 02:16:15 +01:00
|
|
|
};
|
|
|
|
|
2019-03-07 09:12:00 +01:00
|
|
|
function set_invalid_narrow_message(invalid_narrow_message) {
|
|
|
|
var search_string_display = $("#empty_search_stop_words_string");
|
|
|
|
search_string_display.text(invalid_narrow_message);
|
|
|
|
}
|
|
|
|
|
2019-01-28 17:44:48 +01:00
|
|
|
function show_search_query() {
|
2019-03-07 09:27:45 +01:00
|
|
|
// when search bar contains multiple filters, only show search queries
|
|
|
|
var current_filter = narrow_state.filter();
|
|
|
|
var search_query = current_filter.operands("search")[0];
|
2019-01-28 17:44:48 +01:00
|
|
|
var query_words = search_query.split(" ");
|
|
|
|
|
|
|
|
var search_string_display = $("#empty_search_stop_words_string");
|
2019-02-14 04:46:09 +01:00
|
|
|
var query_contains_stop_words = false;
|
2019-01-28 17:44:48 +01:00
|
|
|
|
2019-02-14 04:46:09 +01:00
|
|
|
// Also removes previous search_string if any
|
|
|
|
search_string_display.text(i18n.t("You searched for:"));
|
2019-01-28 17:44:48 +01:00
|
|
|
|
2019-03-07 09:27:45 +01:00
|
|
|
// Add in stream:foo and topic:bar if present
|
|
|
|
if (current_filter.has_operator("stream") || current_filter.has_operator("topic")) {
|
|
|
|
var stream_topic_string = "";
|
|
|
|
var stream = current_filter.operands('stream')[0];
|
|
|
|
var topic = current_filter.operands('topic')[0];
|
|
|
|
if (stream) {
|
|
|
|
stream_topic_string = "stream: " + stream;
|
|
|
|
}
|
|
|
|
if (topic) {
|
|
|
|
stream_topic_string = stream_topic_string + " topic: " + topic;
|
|
|
|
}
|
|
|
|
|
|
|
|
search_string_display.append(' ');
|
|
|
|
search_string_display.append($('<span>').text(stream_topic_string));
|
|
|
|
}
|
|
|
|
|
2019-01-28 17:44:48 +01:00
|
|
|
_.each(query_words, function (query_word) {
|
|
|
|
search_string_display.append(' ');
|
|
|
|
|
|
|
|
// if query contains stop words, it is enclosed by a <del> tag
|
|
|
|
if (_.contains(page_params.stop_words, query_word)) {
|
|
|
|
// stop_words do not need sanitization so this is unnecesary but it is fail-safe.
|
|
|
|
search_string_display.append($('<del>').text(query_word));
|
2019-02-14 04:46:09 +01:00
|
|
|
query_contains_stop_words = true;
|
2019-01-28 17:44:48 +01:00
|
|
|
} else {
|
|
|
|
// We use .text("...") to sanitize the user-given query_string.
|
|
|
|
search_string_display.append($('<span>').text(query_word));
|
|
|
|
}
|
|
|
|
});
|
2019-02-14 04:46:09 +01:00
|
|
|
|
|
|
|
if (query_contains_stop_words) {
|
|
|
|
search_string_display.html(i18n.t(
|
|
|
|
"Some common words were excluded from your search.") + "<br/>" + search_string_display.html());
|
|
|
|
}
|
2019-01-28 17:44:48 +01:00
|
|
|
}
|
|
|
|
|
2013-03-29 19:55:28 +01:00
|
|
|
function pick_empty_narrow_banner() {
|
|
|
|
var default_banner = $('#empty_narrow_message');
|
2017-04-25 15:25:31 +02:00
|
|
|
|
2018-07-07 15:55:39 +02:00
|
|
|
var current_filter = narrow_state.filter();
|
2017-04-25 15:25:31 +02:00
|
|
|
|
2013-04-24 21:40:08 +02:00
|
|
|
if (current_filter === undefined) {
|
2013-03-29 19:55:28 +01:00
|
|
|
return default_banner;
|
|
|
|
}
|
|
|
|
|
2014-02-06 21:41:01 +01:00
|
|
|
var first_term = current_filter.operators()[0];
|
|
|
|
var first_operator = first_term.operator;
|
|
|
|
var first_operand = first_term.operand;
|
2016-08-01 04:31:34 +02:00
|
|
|
var num_operators = current_filter.operators().length;
|
2013-03-29 19:55:28 +01:00
|
|
|
|
2016-08-01 04:31:34 +02:00
|
|
|
if (num_operators !== 1) {
|
2019-03-07 09:12:00 +01:00
|
|
|
// For invalid-multi-operator narrows, we display an invalid narrow message
|
|
|
|
var streams = current_filter.operands("stream");
|
|
|
|
|
|
|
|
var invalid_narrow_message = "";
|
|
|
|
// No message can have multiple streams
|
|
|
|
if (streams.length > 1) {
|
|
|
|
invalid_narrow_message = i18n.t("You are searching for messages that belong to more than one stream, which is not possible.");
|
|
|
|
}
|
|
|
|
// No message can have multiple topics
|
|
|
|
if (current_filter.operands("topic").length > 1) {
|
|
|
|
invalid_narrow_message = i18n.t("You are searching for messages that belong to more than one topic, which is not possible.");
|
|
|
|
}
|
|
|
|
// No message can have multiple senders
|
|
|
|
if (current_filter.operands("sender").length > 1) {
|
|
|
|
invalid_narrow_message = i18n.t("You are searching for messages that are sent by more than one person, which is not possible.");
|
|
|
|
}
|
|
|
|
if (invalid_narrow_message !== "") {
|
|
|
|
set_invalid_narrow_message(invalid_narrow_message);
|
|
|
|
return $("#empty_search_narrow_message");
|
|
|
|
}
|
|
|
|
|
|
|
|
// For empty stream searches within other narrows, we display the stop words
|
2019-03-07 09:27:45 +01:00
|
|
|
if (current_filter.operators("search")) {
|
|
|
|
show_search_query();
|
|
|
|
return $("#empty_search_narrow_message");
|
|
|
|
}
|
|
|
|
// For other multi-operator narrows, we just use the default banner
|
2016-08-01 04:31:34 +02:00
|
|
|
return default_banner;
|
|
|
|
} else if (first_operator === "is") {
|
2013-03-29 19:55:28 +01:00
|
|
|
if (first_operand === "starred") {
|
|
|
|
// You have no starred messages.
|
|
|
|
return $("#empty_star_narrow_message");
|
2013-07-10 03:07:01 +02:00
|
|
|
} else if (first_operand === "mentioned") {
|
2013-05-29 00:33:03 +02:00
|
|
|
return $("#empty_narrow_all_mentioned");
|
2013-07-10 03:22:34 +02:00
|
|
|
} else if (first_operand === "private") {
|
2013-03-29 19:55:28 +01:00
|
|
|
// You have no private messages.
|
2013-04-02 20:57:53 +02:00
|
|
|
return $("#empty_narrow_all_private_message");
|
2017-06-18 23:50:00 +02:00
|
|
|
} else if (first_operand === "unread") {
|
|
|
|
// You have no unread messages.
|
|
|
|
return $("#no_unread_narrow_message");
|
2013-03-29 19:55:28 +01:00
|
|
|
}
|
2018-06-06 18:50:09 +02:00
|
|
|
} else if (first_operator === "stream" && !stream_data.is_subscribed(first_operand)) {
|
2018-01-04 08:07:19 +01:00
|
|
|
// You are narrowed to a stream which does not exist or is a private stream
|
|
|
|
// in which you were never subscribed.
|
|
|
|
var stream_sub = stream_data.get_sub(narrow_state.stream());
|
2019-03-08 22:12:47 +01:00
|
|
|
if (!stream_sub || !stream_sub.should_display_subscription_button) {
|
2017-01-25 19:13:10 +01:00
|
|
|
return $("#nonsubbed_private_nonexistent_stream_narrow_message");
|
|
|
|
}
|
2013-03-29 19:55:28 +01:00
|
|
|
return $("#nonsubbed_stream_narrow_message");
|
|
|
|
} else if (first_operator === "search") {
|
|
|
|
// You are narrowed to empty search results.
|
2019-01-28 17:44:48 +01:00
|
|
|
show_search_query();
|
2013-03-29 19:55:28 +01:00
|
|
|
return $("#empty_search_narrow_message");
|
2013-04-02 20:57:53 +02:00
|
|
|
} else if (first_operator === "pm-with") {
|
2018-05-28 14:10:33 +02:00
|
|
|
if (!people.is_valid_bulk_emails_for_compose(first_operand.split(','))) {
|
|
|
|
if (first_operand.indexOf(',') === -1) {
|
|
|
|
return $("#non_existing_user");
|
|
|
|
}
|
|
|
|
return $("#non_existing_users");
|
|
|
|
}
|
2013-04-02 20:57:53 +02:00
|
|
|
if (first_operand.indexOf(',') === -1) {
|
|
|
|
// You have no private messages with this person
|
2018-11-28 20:59:16 +01:00
|
|
|
if (people.is_current_user(first_operand)) {
|
|
|
|
return $("#empty_narrow_self_private_message");
|
|
|
|
}
|
2013-04-02 20:57:53 +02:00
|
|
|
return $("#empty_narrow_private_message");
|
|
|
|
}
|
2016-12-02 21:34:35 +01:00
|
|
|
return $("#empty_narrow_multi_private_message");
|
2016-07-29 16:15:50 +02:00
|
|
|
} else if (first_operator === "sender") {
|
|
|
|
if (people.get_by_email(first_operand)) {
|
|
|
|
return $("#silent_user");
|
|
|
|
}
|
2016-12-02 21:34:35 +01:00
|
|
|
return $("#non_existing_user");
|
2017-09-24 19:26:51 +02:00
|
|
|
} else if (first_operator === "group-pm-with") {
|
|
|
|
return $("#empty_narrow_group_private_message");
|
2013-03-29 19:55:28 +01:00
|
|
|
}
|
|
|
|
return default_banner;
|
|
|
|
}
|
|
|
|
|
|
|
|
exports.show_empty_narrow_message = function () {
|
|
|
|
$(".empty_feed_notice").hide();
|
|
|
|
pick_empty_narrow_banner().show();
|
2018-08-06 00:58:07 +02:00
|
|
|
$("#left_bar_compose_reply_button_big").attr("title", i18n.t("There are no messages to reply to."));
|
|
|
|
$("#left_bar_compose_reply_button_big").attr("disabled", "disabled");
|
2013-03-29 19:55:28 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
exports.hide_empty_narrow_message = function () {
|
|
|
|
$(".empty_feed_notice").hide();
|
2018-08-06 00:58:07 +02:00
|
|
|
$("#left_bar_compose_reply_button_big").attr("title", i18n.t("Reply (r)"));
|
|
|
|
$("#left_bar_compose_reply_button_big").removeAttr("disabled");
|
2013-03-29 19:55:28 +01:00
|
|
|
};
|
|
|
|
|
2012-10-18 20:12:04 +02:00
|
|
|
return exports;
|
|
|
|
|
|
|
|
}());
|
2013-07-28 23:03:43 +02:00
|
|
|
if (typeof module !== 'undefined') {
|
|
|
|
module.exports = narrow;
|
|
|
|
}
|
2018-05-28 08:04:36 +02:00
|
|
|
window.narrow = narrow;
|