mirror of
https://github.com/zulip/zulip.git
synced 2025-10-28 18:43:52 +00:00
Ever since we started bundling the app with webpack, there’s been less and less overlap between our ‘static’ directory (files belonging to the frontend app) and Django’s interpretation of the ‘static’ directory (files served directly to the web). Split the app out to its own ‘web’ directory outside of ‘static’, and remove all the custom collectstatic --ignore rules. This makes it much clearer what’s actually being served to the web, and what’s being bundled by webpack. It also shrinks the release tarball by 3%. Signed-off-by: Anders Kaseorg <anders@zulip.com>
287 lines
8.9 KiB
JavaScript
287 lines
8.9 KiB
JavaScript
import $ from "jquery";
|
|
|
|
import * as message_flags from "./message_flags";
|
|
import * as message_lists from "./message_lists";
|
|
import * as message_viewport from "./message_viewport";
|
|
import * as recent_topics_util from "./recent_topics_util";
|
|
import * as rows from "./rows";
|
|
|
|
/*
|
|
This library implements two related, similar concepts:
|
|
|
|
- condensing, i.e. cutting off messages taller than about a half
|
|
screen so that they aren't distractingly tall (and offering a button
|
|
to uncondense them).
|
|
|
|
- Collapsing, i.e. taking a message and reducing its height to a
|
|
single line, with a button to see the content.
|
|
|
|
*/
|
|
|
|
const _message_content_height_cache = new Map();
|
|
|
|
function show_more_link($row) {
|
|
$row.find(".message_condenser").hide();
|
|
$row.find(".message_expander").show();
|
|
}
|
|
|
|
function show_condense_link($row) {
|
|
$row.find(".message_expander").hide();
|
|
$row.find(".message_condenser").show();
|
|
}
|
|
|
|
function condense_row($row) {
|
|
const $content = $row.find(".message_content");
|
|
$content.addClass("condensed");
|
|
show_more_link($row);
|
|
}
|
|
|
|
function uncondense_row($row) {
|
|
const $content = $row.find(".message_content");
|
|
$content.removeClass("condensed");
|
|
show_condense_link($row);
|
|
}
|
|
|
|
export function uncollapse($row) {
|
|
// Uncollapse a message, restoring the condensed message [More] or
|
|
// [Show less] link if necessary.
|
|
const message = message_lists.current.get(rows.id($row));
|
|
message.collapsed = false;
|
|
message_flags.save_uncollapsed(message);
|
|
|
|
const process_row = function process_row($row) {
|
|
const $content = $row.find(".message_content");
|
|
$content.removeClass("collapsed");
|
|
|
|
if (message.condensed === true) {
|
|
// This message was condensed by the user, so re-show the
|
|
// [More] link.
|
|
condense_row($row);
|
|
} else if (message.condensed === false) {
|
|
// This message was un-condensed by the user, so re-show the
|
|
// [Show less] link.
|
|
uncondense_row($row);
|
|
} else if ($content.hasClass("could-be-condensed")) {
|
|
// By default, condense a long message.
|
|
condense_row($row);
|
|
} else {
|
|
// This was a short message, no more need for a [More] link.
|
|
$row.find(".message_expander").hide();
|
|
}
|
|
};
|
|
|
|
// We also need to collapse this message in the home view
|
|
const $home_row = message_lists.home.get_row(rows.id($row));
|
|
|
|
process_row($row);
|
|
process_row($home_row);
|
|
}
|
|
|
|
export function collapse($row) {
|
|
// Collapse a message, hiding the condensed message [More] or
|
|
// [Show less] link if necessary.
|
|
const message = message_lists.current.get(rows.id($row));
|
|
message.collapsed = true;
|
|
|
|
if (message.locally_echoed) {
|
|
// Trying to collapse a locally echoed message is
|
|
// very rare, and in our current implementation the
|
|
// server response overwrites the flag, so we just
|
|
// punt for now.
|
|
return;
|
|
}
|
|
|
|
message_flags.save_collapsed(message);
|
|
|
|
const process_row = function process_row($row) {
|
|
$row.find(".message_content").addClass("collapsed");
|
|
show_more_link($row);
|
|
};
|
|
|
|
// We also need to collapse this message in the home view
|
|
const $home_row = message_lists.home.get_row(rows.id($row));
|
|
|
|
process_row($row);
|
|
process_row($home_row);
|
|
}
|
|
|
|
export function toggle_collapse(message) {
|
|
if (message.is_me_message) {
|
|
// Disabled temporarily because /me messages don't have a
|
|
// styling for collapsing /me messages (they only recently
|
|
// added multi-line support). See also popovers.js.
|
|
return;
|
|
}
|
|
|
|
// This function implements a multi-way toggle, to try to do what
|
|
// the user wants for messages:
|
|
//
|
|
// * If the message is currently showing any [More] link, either
|
|
// because it was previously condensed or collapsed, fully display it.
|
|
// * If the message is fully visible, either because it's too short to
|
|
// condense or because it's already uncondensed, collapse it
|
|
|
|
const $row = message_lists.current.get_row(message.id);
|
|
if (!$row) {
|
|
return;
|
|
}
|
|
|
|
const $content = $row.find(".message_content");
|
|
const is_condensable = $content.hasClass("could-be-condensed");
|
|
const is_condensed = $content.hasClass("condensed");
|
|
if (message.collapsed) {
|
|
if (is_condensable) {
|
|
message.condensed = true;
|
|
$content.addClass("condensed");
|
|
show_message_expander($row);
|
|
$row.find(".message_condenser").hide();
|
|
}
|
|
uncollapse($row);
|
|
} else {
|
|
if (is_condensed) {
|
|
message.condensed = false;
|
|
$content.removeClass("condensed");
|
|
hide_message_expander($row);
|
|
$row.find(".message_condenser").show();
|
|
} else {
|
|
collapse($row);
|
|
}
|
|
}
|
|
}
|
|
|
|
export function clear_message_content_height_cache() {
|
|
_message_content_height_cache.clear();
|
|
}
|
|
|
|
export function un_cache_message_content_height(message_id) {
|
|
_message_content_height_cache.delete(message_id);
|
|
}
|
|
|
|
function get_message_height(elem, message_id) {
|
|
if (_message_content_height_cache.has(message_id)) {
|
|
return _message_content_height_cache.get(message_id);
|
|
}
|
|
|
|
// shown to be ~2.5x faster than Node.getBoundingClientRect().
|
|
const height = elem.offsetHeight;
|
|
if (!recent_topics_util.is_visible()) {
|
|
_message_content_height_cache.set(message_id, height);
|
|
}
|
|
return height;
|
|
}
|
|
|
|
export function hide_message_expander($row) {
|
|
if ($row.find(".could-be-condensed").length !== 0) {
|
|
$row.find(".message_expander").hide();
|
|
}
|
|
}
|
|
|
|
export function hide_message_condenser($row) {
|
|
if ($row.find(".could-be-condensed").length !== 0) {
|
|
$row.find(".message_condenser").hide();
|
|
}
|
|
}
|
|
|
|
export function show_message_expander($row) {
|
|
if ($row.find(".could-be-condensed").length !== 0) {
|
|
$row.find(".message_expander").show();
|
|
}
|
|
}
|
|
|
|
export function show_message_condenser($row) {
|
|
if ($row.find(".could-be-condensed").length !== 0) {
|
|
$row.find(".message_condenser").show();
|
|
}
|
|
}
|
|
|
|
export function condense_and_collapse(elems) {
|
|
const height_cutoff = message_viewport.height() * 0.65;
|
|
|
|
for (const elem of elems) {
|
|
const $content = $(elem).find(".message_content");
|
|
|
|
if ($content.length !== 1) {
|
|
// We could have a "/me did this" message or something
|
|
// else without a `message_content` div.
|
|
continue;
|
|
}
|
|
|
|
const message_id = rows.id($(elem));
|
|
|
|
if (!message_id) {
|
|
continue;
|
|
}
|
|
|
|
const message = message_lists.current.get(message_id);
|
|
if (message === undefined) {
|
|
continue;
|
|
}
|
|
|
|
const message_height = get_message_height(elem, message.id);
|
|
const long_message = message_height > height_cutoff;
|
|
if (long_message) {
|
|
// All long messages are flagged as such.
|
|
$content.addClass("could-be-condensed");
|
|
} else {
|
|
$content.removeClass("could-be-condensed");
|
|
}
|
|
|
|
// If message.condensed is defined, then the user has manually
|
|
// specified whether this message should be expanded or condensed.
|
|
if (message.condensed === true) {
|
|
condense_row($(elem));
|
|
continue;
|
|
}
|
|
|
|
if (message.condensed === false) {
|
|
uncondense_row($(elem));
|
|
continue;
|
|
}
|
|
|
|
if (long_message) {
|
|
// By default, condense a long message.
|
|
condense_row($(elem));
|
|
} else {
|
|
$content.removeClass("condensed");
|
|
$(elem).find(".message_expander").hide();
|
|
}
|
|
|
|
// Completely hide the message and replace it with a [More]
|
|
// link if the user has collapsed it.
|
|
if (message.collapsed) {
|
|
$content.addClass("collapsed");
|
|
$(elem).find(".message_expander").show();
|
|
}
|
|
}
|
|
}
|
|
|
|
export function initialize() {
|
|
$("#message_feed_container").on("click", ".message_expander", function (e) {
|
|
// Expanding a message can mean either uncollapsing or
|
|
// uncondensing it.
|
|
const $row = $(this).closest(".message_row");
|
|
const message = message_lists.current.get(rows.id($row));
|
|
const $content = $row.find(".message_content");
|
|
if (message.collapsed) {
|
|
// Uncollapse.
|
|
uncollapse($row);
|
|
} else if ($content.hasClass("condensed")) {
|
|
// Uncondense (show the full long message).
|
|
message.condensed = false;
|
|
$content.removeClass("condensed");
|
|
$(this).hide();
|
|
$row.find(".message_condenser").show();
|
|
}
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
});
|
|
|
|
$("#message_feed_container").on("click", ".message_condenser", function (e) {
|
|
const $row = $(this).closest(".message_row");
|
|
message_lists.current.get(rows.id($row)).condensed = true;
|
|
condense_row($row);
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
});
|
|
}
|