zulip/static/js/condense.js

246 lines
8.0 KiB
JavaScript
Raw Normal View History

/*
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.
*/
var Dict = require('./dict').Dict;
var _message_content_height_cache = new Dict();
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) {
var content = row.find(".message_content");
content.addClass("condensed");
show_more_link(row);
}
function uncondense_row(row) {
var content = row.find(".message_content");
content.removeClass("condensed");
show_condense_link(row);
}
exports.uncollapse = function (row) {
// Uncollapse a message, restoring the condensed message [More] or
// [Condense] link if necessary.
var message = current_msg_list.get(rows.id(row));
message.collapsed = false;
message_flags.save_uncollapsed(message);
Fix collapsing messages in narrowed views. First user-fasing problem is that when user click to "Collapse" button of message from narrowed list, buttons "Uncollapse" and "[More...]" does not work. Second, is that when user collapse/uncollapse some message from narrowed list, the collapsing/uncollapsing of the same message in home list does not work in appropriate way. In "popovers.js" there is the function that is called on click to the buttons "Collapse" or "Un-collapse". It should show and hide body of a message. If a message list is narrowed, it should show/hide message in home list too. So, the first problem is that "toggle_row()" in this function call methods "collapse(row)" or "uncollapse(row)" from "condense.js" twice (for row and home_row) using condition "if (message.collapsed)". When it happen the first time, the variable "message.collapsed" is changed. That is why next call of "toggle_row()" work incorrectly. The second problem is that the function in "condense.js" that is called on click to the button "[More...]" contains no code for collapsing/uncollapsing message from home list. It just calls "collapse(row)" or "uncollapse(row)" for row from narrowed list. Now, functions "collapse(row)" and "uncollapse(row)" get row from current list and change both messages (from current list and home list). On-click functions call them just once for making all of needed message changes. So, when user collapse or uncollapse message from home or narrowed list it works correctly. Fixes: #516
2016-03-13 19:05:10 +01:00
var process_row = function process_row(row) {
var 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
// [Condense] 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
var home_row = home_msg_list.get_row(rows.id(row));
process_row(row);
process_row(home_row);
};
exports.collapse = function (row) {
// Collapse a message, hiding the condensed message [More] or
// [Condense] link if necessary.
var message = current_msg_list.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);
Fix collapsing messages in narrowed views. First user-fasing problem is that when user click to "Collapse" button of message from narrowed list, buttons "Uncollapse" and "[More...]" does not work. Second, is that when user collapse/uncollapse some message from narrowed list, the collapsing/uncollapsing of the same message in home list does not work in appropriate way. In "popovers.js" there is the function that is called on click to the buttons "Collapse" or "Un-collapse". It should show and hide body of a message. If a message list is narrowed, it should show/hide message in home list too. So, the first problem is that "toggle_row()" in this function call methods "collapse(row)" or "uncollapse(row)" from "condense.js" twice (for row and home_row) using condition "if (message.collapsed)". When it happen the first time, the variable "message.collapsed" is changed. That is why next call of "toggle_row()" work incorrectly. The second problem is that the function in "condense.js" that is called on click to the button "[More...]" contains no code for collapsing/uncollapsing message from home list. It just calls "collapse(row)" or "uncollapse(row)" for row from narrowed list. Now, functions "collapse(row)" and "uncollapse(row)" get row from current list and change both messages (from current list and home list). On-click functions call them just once for making all of needed message changes. So, when user collapse or uncollapse message from home or narrowed list it works correctly. Fixes: #516
2016-03-13 19:05:10 +01:00
var 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
var home_row = home_msg_list.get_row(rows.id(row));
process_row(row);
process_row(home_row);
};
exports.toggle_collapse = function (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
var row = current_msg_list.get_row(message.id);
if (!row) {
return;
}
var content = row.find(".message_content");
var is_condensable = content.hasClass("could-be-condensed");
var is_condensed = content.hasClass("condensed");
if (message.collapsed) {
if (is_condensable) {
message.condensed = true;
content.addClass("condensed");
exports.show_message_expander(row);
row.find(".message_condenser").hide();
}
exports.uncollapse(row);
} else {
if (is_condensed) {
message.condensed = false;
content.removeClass("condensed");
exports.hide_message_expander(row);
row.find(".message_condenser").show();
} else {
exports.collapse(row);
}
}
};
exports.clear_message_content_height_cache = function () {
_message_content_height_cache = new Dict();
};
exports.un_cache_message_content_height = function (message_id) {
_message_content_height_cache.del(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().
var height = elem.offsetHeight;
_message_content_height_cache.set(message_id, height);
return height;
}
exports.hide_message_expander = function (row) {
if (row.find(".could-be-condensed").length !== 0) {
row.find(".message_expander").hide();
}
};
exports.show_message_expander = function (row) {
if (row.find(".could-be-condensed").length !== 0) {
row.find(".message_expander").show();
}
};
exports.condense_and_collapse = function (elems) {
var height_cutoff = message_viewport.height() * 0.65;
_.each(elems, function (elem) {
var content = $(elem).find(".message_content");
var message = current_msg_list.get(rows.id($(elem)));
if (content !== undefined && message !== undefined) {
var message_height = get_message_height(elem, message.id);
var 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));
return;
} else if (message.condensed === false) {
uncondense_row($(elem));
return;
} else 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();
}
}
});
};
exports.initialize = function () {
$("#home").on("click", ".message_expander", function () {
// Expanding a message can mean either uncollapsing or
// uncondensing it.
var row = $(this).closest(".message_row");
var message = current_msg_list.get(rows.id(row));
var content = row.find(".message_content");
if (message.collapsed) {
// Uncollapse.
exports.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();
}
});
$("#home").on("click", ".message_condenser", function () {
var row = $(this).closest(".message_row");
current_msg_list.get(rows.id(row)).condensed = true;
condense_row(row);
});
};
window.condense = exports;