2019-11-02 00:06:25 +01:00
|
|
|
const render_more_topics = require('../templates/more_topics.hbs');
|
2020-01-30 13:02:50 +01:00
|
|
|
const render_more_topics_spinner = require('../templates/more_topics_spinner.hbs');
|
2019-11-02 00:06:25 +01:00
|
|
|
const render_topic_list_item = require('../templates/topic_list_item.hbs');
|
2020-02-01 05:02:11 +01:00
|
|
|
const IntDict = require('./int_dict').IntDict;
|
2020-01-18 13:53:12 +01:00
|
|
|
const topic_list_data = require('./topic_list_data');
|
2019-02-08 11:56:33 +01:00
|
|
|
|
2019-03-09 16:32:41 +01:00
|
|
|
/*
|
2020-02-01 05:02:11 +01:00
|
|
|
Track all active widgets with an IntDict.
|
2019-03-09 16:32:41 +01:00
|
|
|
|
|
|
|
(We have at max one for now, but we may
|
|
|
|
eventually allow multiple streams to be
|
|
|
|
expanded.)
|
|
|
|
*/
|
|
|
|
|
2020-02-01 05:02:11 +01:00
|
|
|
const active_widgets = new IntDict();
|
2016-10-27 01:36:20 +02:00
|
|
|
|
2016-11-10 16:15:12 +01:00
|
|
|
// We know whether we're zoomed or not.
|
2019-11-02 00:06:25 +01:00
|
|
|
let zoomed = false;
|
2016-11-10 16:15:12 +01:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
exports.update = function () {
|
|
|
|
for (const widget of active_widgets.values()) {
|
|
|
|
widget.build();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-10-27 01:53:47 +02:00
|
|
|
exports.remove_expanded_topics = function () {
|
2017-03-05 17:28:40 +01:00
|
|
|
stream_popover.hide_topic_popover();
|
2016-10-27 01:53:47 +02:00
|
|
|
|
2020-02-03 08:51:09 +01:00
|
|
|
for (const widget of active_widgets.values()) {
|
2019-03-09 16:32:41 +01:00
|
|
|
widget.remove();
|
2020-02-03 08:51:09 +01:00
|
|
|
}
|
2019-03-09 16:32:41 +01:00
|
|
|
|
|
|
|
active_widgets.clear();
|
2016-11-10 15:35:14 +01:00
|
|
|
};
|
2016-10-27 01:36:20 +02:00
|
|
|
|
2017-08-11 00:30:23 +02:00
|
|
|
exports.close = function () {
|
|
|
|
zoomed = false;
|
|
|
|
exports.remove_expanded_topics();
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.zoom_out = function () {
|
|
|
|
zoomed = false;
|
2019-03-09 16:32:41 +01:00
|
|
|
|
2020-02-04 23:46:56 +01:00
|
|
|
const stream_ids = Array.from(active_widgets.keys());
|
2019-03-09 16:32:41 +01:00
|
|
|
|
|
|
|
if (stream_ids.length !== 1) {
|
|
|
|
blueslip.error('Unexpected number of topic lists to zoom out.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const stream_id = stream_ids[0];
|
|
|
|
const widget = active_widgets.get(stream_id);
|
|
|
|
const parent_widget = widget.get_parent();
|
2019-03-09 16:32:41 +01:00
|
|
|
|
|
|
|
exports.rebuild(parent_widget, stream_id);
|
2017-08-11 00:30:23 +02:00
|
|
|
};
|
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
exports.keyed_topic_li = (convo) => {
|
|
|
|
const render = () => {
|
|
|
|
return render_topic_list_item(convo);
|
|
|
|
};
|
2016-11-12 01:01:20 +01:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
const eq = (other) => {
|
|
|
|
return _.isEqual(convo, other.convo);
|
|
|
|
};
|
2016-11-12 01:01:20 +01:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
const key = 't:' + convo.topic_name;
|
2016-10-29 19:39:47 +02:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
return {
|
|
|
|
key: key,
|
|
|
|
render: render,
|
|
|
|
convo: convo,
|
|
|
|
eq: eq,
|
|
|
|
};
|
|
|
|
};
|
2019-03-09 16:32:41 +01:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
exports.more_li = (more_topics_unreads) => {
|
|
|
|
const render = () => {
|
|
|
|
return render_more_topics({
|
|
|
|
more_topics_unreads: more_topics_unreads,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const eq = (other) => {
|
|
|
|
return other.more_items &&
|
|
|
|
more_topics_unreads === other.more_topics_unreads;
|
|
|
|
};
|
|
|
|
|
|
|
|
const key = 'more';
|
2019-03-09 16:32:41 +01:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
return {
|
|
|
|
key: key,
|
|
|
|
more_items: true,
|
|
|
|
more_topics_unreads: more_topics_unreads,
|
|
|
|
render: render,
|
|
|
|
eq: eq,
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
exports.spinner_li = () => {
|
|
|
|
const render = () => {
|
|
|
|
return render_more_topics_spinner();
|
|
|
|
};
|
|
|
|
|
|
|
|
const eq = (other) => {
|
|
|
|
return other.spinner;
|
|
|
|
};
|
|
|
|
|
|
|
|
const key = 'more';
|
|
|
|
|
|
|
|
return {
|
|
|
|
key: key,
|
|
|
|
spinner: true,
|
|
|
|
render: render,
|
|
|
|
eq: eq,
|
|
|
|
};
|
2016-10-27 01:36:20 +02:00
|
|
|
};
|
|
|
|
|
2017-09-25 16:51:16 +02:00
|
|
|
exports.widget = function (parent_elem, my_stream_id) {
|
2019-11-02 00:06:25 +01:00
|
|
|
const self = {};
|
2016-10-27 02:02:40 +02:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
self.prior_dom = undefined;
|
|
|
|
|
|
|
|
self.build_list = function (spinner) {
|
2020-01-18 13:53:12 +01:00
|
|
|
const list_info = topic_list_data.get_list_info(
|
2020-01-30 12:45:12 +01:00
|
|
|
my_stream_id, zoomed);
|
2020-01-18 13:53:12 +01:00
|
|
|
|
2020-01-17 22:56:00 +01:00
|
|
|
const num_possible_topics = list_info.num_possible_topics;
|
|
|
|
const more_topics_unreads = list_info.more_topics_unreads;
|
|
|
|
|
2020-01-30 12:54:36 +01:00
|
|
|
const is_showing_all_possible_topics =
|
|
|
|
list_info.items.length === num_possible_topics &&
|
|
|
|
topic_data.is_complete_for_stream_id(my_stream_id);
|
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
const attrs = [
|
|
|
|
['class', 'topic-list'],
|
|
|
|
];
|
2020-01-17 22:56:00 +01:00
|
|
|
|
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
|
|
|
const nodes = list_info.items.map(exports.keyed_topic_li);
|
2016-10-29 20:19:25 +02:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
if (spinner) {
|
|
|
|
nodes.push(exports.spinner_li());
|
|
|
|
} else if (!is_showing_all_possible_topics) {
|
|
|
|
nodes.push(exports.more_li(more_topics_unreads));
|
|
|
|
}
|
2016-10-27 02:02:40 +02:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
const dom = vdom.ul({
|
|
|
|
attrs: attrs,
|
|
|
|
keyed_nodes: nodes,
|
|
|
|
});
|
2020-01-30 13:02:50 +01:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
return dom;
|
2017-09-22 20:37:05 +02:00
|
|
|
};
|
2016-10-27 02:02:40 +02:00
|
|
|
|
2016-11-10 20:05:14 +01:00
|
|
|
self.get_parent = function () {
|
|
|
|
return parent_elem;
|
|
|
|
};
|
|
|
|
|
2017-05-14 18:06:57 +02:00
|
|
|
self.get_stream_id = function () {
|
|
|
|
return my_stream_id;
|
2016-11-10 20:19:22 +01:00
|
|
|
};
|
|
|
|
|
2016-11-10 15:35:14 +01:00
|
|
|
self.remove = function () {
|
2020-01-31 20:15:46 +01:00
|
|
|
parent_elem.find('.topic-list').remove();
|
|
|
|
self.prior_dom = undefined;
|
2016-11-10 15:35:14 +01:00
|
|
|
};
|
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
self.build = function (spinner) {
|
|
|
|
const new_dom = self.build_list(spinner);
|
2017-09-22 03:26:10 +02:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
function replace_content(html) {
|
|
|
|
self.remove();
|
|
|
|
parent_elem.append(html);
|
2019-08-29 01:41:23 +02:00
|
|
|
}
|
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
function find() {
|
|
|
|
return parent_elem.find('.topic-list');
|
2016-10-29 21:01:07 +02:00
|
|
|
}
|
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
vdom.update(replace_content, find, new_dom, self.prior_dom);
|
2017-09-22 00:12:55 +02:00
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
self.prior_dom = new_dom;
|
2017-09-22 22:54:10 +02:00
|
|
|
};
|
2016-11-10 20:05:14 +01:00
|
|
|
|
2016-10-29 20:19:25 +02:00
|
|
|
return self;
|
2016-10-27 02:02:40 +02:00
|
|
|
};
|
|
|
|
|
2017-08-11 00:29:35 +02:00
|
|
|
exports.active_stream_id = function () {
|
2020-02-04 23:46:56 +01:00
|
|
|
const stream_ids = Array.from(active_widgets.keys());
|
2019-03-09 16:32:41 +01:00
|
|
|
|
|
|
|
if (stream_ids.length !== 1) {
|
2017-08-11 00:29:35 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-03-09 16:32:41 +01:00
|
|
|
return stream_ids[0];
|
2017-08-11 00:29:35 +02:00
|
|
|
};
|
|
|
|
|
2018-09-10 14:52:58 +02:00
|
|
|
exports.get_stream_li = function () {
|
2020-02-04 23:46:56 +01:00
|
|
|
const widgets = Array.from(active_widgets.values());
|
2019-03-09 16:32:41 +01:00
|
|
|
|
|
|
|
if (widgets.length !== 1) {
|
2018-09-10 14:52:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const stream_li = widgets[0].get_parent();
|
2018-09-10 14:52:58 +02:00
|
|
|
return stream_li;
|
|
|
|
};
|
|
|
|
|
2017-05-14 18:06:57 +02:00
|
|
|
exports.rebuild = function (stream_li, stream_id) {
|
2020-01-31 20:15:46 +01:00
|
|
|
const active_widget = active_widgets.get(stream_id);
|
|
|
|
|
|
|
|
if (active_widget) {
|
|
|
|
active_widget.build();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-27 02:33:24 +02:00
|
|
|
exports.remove_expanded_topics();
|
2019-11-02 00:06:25 +01:00
|
|
|
const widget = exports.widget(stream_li, stream_id);
|
2020-01-17 22:41:13 +01:00
|
|
|
widget.build();
|
2019-03-09 16:32:41 +01:00
|
|
|
|
|
|
|
active_widgets.set(stream_id, widget);
|
2016-10-27 02:33:24 +02:00
|
|
|
};
|
|
|
|
|
2016-11-10 16:15:12 +01:00
|
|
|
// For zooming, we only do topic-list stuff here...let stream_list
|
|
|
|
// handle hiding/showing the non-narrowed streams
|
|
|
|
exports.zoom_in = function () {
|
|
|
|
zoomed = true;
|
2016-11-10 20:46:01 +01:00
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const stream_id = exports.active_stream_id();
|
2019-03-09 16:32:41 +01:00
|
|
|
if (!stream_id) {
|
2016-11-10 20:46:01 +01:00
|
|
|
blueslip.error('Cannot find widget for topic history zooming.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-11-02 00:06:25 +01:00
|
|
|
const active_widget = active_widgets.get(stream_id);
|
2019-03-09 16:32:41 +01:00
|
|
|
|
2017-08-08 20:29:15 +02:00
|
|
|
function on_success() {
|
2019-03-09 16:32:41 +01:00
|
|
|
if (!active_widgets.has(stream_id)) {
|
2017-09-22 17:34:50 +02:00
|
|
|
blueslip.warn('User re-narrowed before topic history was returned.');
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!zoomed) {
|
|
|
|
blueslip.warn('User zoomed out before topic history was returned.');
|
|
|
|
// Note that we could attempt to re-draw the zoomed out topic list
|
|
|
|
// here, given that we have more history, but that might be more
|
|
|
|
// confusing than helpful to a user who is likely trying to browse
|
|
|
|
// other streams.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-31 20:15:46 +01:00
|
|
|
active_widget.build();
|
2017-08-08 20:29:15 +02:00
|
|
|
}
|
|
|
|
|
2019-03-01 01:40:05 +01:00
|
|
|
ui.get_scroll_element($('#stream-filters-container')).scrollTop(0);
|
2020-01-31 20:15:46 +01:00
|
|
|
|
|
|
|
const spinner = true;
|
|
|
|
active_widget.build(spinner);
|
|
|
|
|
2017-09-21 19:03:23 +02:00
|
|
|
topic_data.get_server_history(stream_id, on_success);
|
2016-11-10 16:15:12 +01:00
|
|
|
};
|
|
|
|
|
2018-09-10 14:52:58 +02:00
|
|
|
exports.initialize = function () {
|
2016-11-05 20:13:36 +01:00
|
|
|
$('#stream_filters').on('click', '.topic-box', function (e) {
|
2016-10-27 03:47:05 +02:00
|
|
|
if (e.metaKey || e.ctrlKey) {
|
|
|
|
return;
|
|
|
|
}
|
2019-08-29 01:41:23 +02:00
|
|
|
if ($(e.target).closest('.show-more-topics').length > 0) {
|
|
|
|
return;
|
|
|
|
}
|
2016-10-27 03:47:05 +02:00
|
|
|
|
|
|
|
// In a more componentized world, we would delegate some
|
|
|
|
// of this stuff back up to our parents.
|
|
|
|
|
2019-12-30 12:51:16 +01:00
|
|
|
const stream_row = $(e.target).parents('.narrow-filter');
|
|
|
|
const stream_id = parseInt(stream_row.attr('data-stream-id'), 10);
|
2019-11-02 00:06:25 +01:00
|
|
|
const sub = stream_data.get_sub_by_id(stream_id);
|
|
|
|
const topic = $(e.target).parents('li').attr('data-topic-name');
|
2016-10-27 03:47:05 +02:00
|
|
|
|
2018-05-06 21:43:17 +02:00
|
|
|
narrow.activate([
|
|
|
|
{operator: 'stream', operand: sub.name},
|
|
|
|
{operator: 'topic', operand: topic}],
|
2018-04-23 06:02:11 +02:00
|
|
|
{trigger: 'sidebar'});
|
2016-10-27 03:47:05 +02:00
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2016-10-27 01:36:20 +02:00
|
|
|
|
2019-10-25 09:45:13 +02:00
|
|
|
window.topic_list = exports;
|