Reimplement collapsing, for realsies this time.

We no longer break random things! Its pretty grand, actually.

This reworks and reverts commit fbadd6e854722e41cccd2535748ee47f4efd657b.

Conflicts:
	zephyr/static/js/zephyr.js

(imported from commit 534a120290855d3bf2cf979ac174267c2d07bf68)
This commit is contained in:
Luke Faraone 2012-09-13 16:00:11 -04:00
parent 8aded489b8
commit c5d1897ab3
4 changed files with 160 additions and 88 deletions

View File

@ -1,10 +1,14 @@
<div id="wrapper"> <div id="wrapper">
<div class="zephyr_list" id="main_div"> <div class="zephyr_list" id="main_div">
<br/><br/> <br/><br/>
<table class="zephyr_table" id="table"> <table class="zephyr_table focused_table" id="table">
<tbody> <tbody>
</tbody> </tbody>
</table> </table>
<table class="zephyr_table" id="filtered_table">
<tbody>
</tbody>
</table>
<br/><br/> <br/><br/>
<div class="row" id="narrowbox"> <div class="row" id="narrowbox">
<div class="input-prepend input-append pull-left"> <div class="input-prepend input-append pull-left">

View File

@ -1,7 +1,8 @@
{{! Client-side Mustache template for rendering zephyrs.}} {{! Client-side Mustache template for rendering zephyrs.}}
<tr id="{{id}}" class="zephyr_row" onmouseover="update_pointer_by_id({{id}});"> <tr zid="{{id}}" class="zephyr_row" onmouseover="update_pointer_by_id({{id}});">
<td class="pointer"><p></p></td> <td class="pointer"><p></p></td>
<td class="zephyr_recipient"><p onclick="select_zephyr({{id}})"> <td class="zephyr_recipient"><p onclick="select_zephyr({{id}})">
{{#include_recipient}}
{{#is_huddle}} {{#is_huddle}}
<span class="hidden zephyr_huddle_recipients_list">{{#display_recipient}}{{name}},{{/display_recipient}}</span> <span class="hidden zephyr_huddle_recipients_list">{{#display_recipient}}{{name}},{{/display_recipient}}</span>
{{#display_recipient}} {{#display_recipient}}
@ -22,14 +23,17 @@
<span class="zephyr_label_clickable zephyr_instance" <span class="zephyr_label_clickable zephyr_instance"
onclick="select_zephyr({{id}}); narrow_instance();">{{instance}}</span> onclick="select_zephyr({{id}}); narrow_instance();">{{instance}}</span>
{{/is_class}} {{/is_class}}
{{/include_recipient}}
<br /> <br />
</td> </td>
<td class="messagebox" onclick="select_zephyr({{id}}); respond_to_zephyr();"> <td class="messagebox{{^include_sender}} collapsed_child{{/include_sender}}" onclick="select_zephyr({{id}}); respond_to_zephyr();">
{{#include_sender}}
<img class="profile_picture" src="http://www.gravatar.com/avatar/{{gravatar_hash}}?d=identicon&s=30"/> <img class="profile_picture" src="http://www.gravatar.com/avatar/{{gravatar_hash}}?d=identicon&s=30"/>
<span class="zephyr_label_clickable zephyr_sender" onmouseover="show_email({{id}});" onmouseout="hide_email({{id}});"> <span class="zephyr_label_clickable zephyr_sender" onmouseover="show_email({{id}});" onmouseout="hide_email({{id}});">
<span class="zephyr_sender_name">{{sender_name}}</span> <span class="zephyr_sender_email invisible">{{sender_email}}</span> <span class="zephyr_sender_name">{{sender_name}}</span> <span class="zephyr_sender_email invisible">{{sender_email}}</span>
<span class="zephyr_sender_username">{{sender}}</span> <span class="zephyr_sender_username">{{sender}}</span>
</span> </span>
{{/include_sender}}
<span class="zephyr_time" title="{{full_date_str}}">{{timestr}}</span> <span class="zephyr_time" title="{{full_date_str}}">{{timestr}}</span>
<div class="zephyr_content">{{{content}}}</div> <div class="zephyr_content">{{{content}}}</div>
</td> </td>

View File

@ -244,19 +244,19 @@ function get_all_zephyr_rows() {
} }
function get_next_visible(zephyr_row) { function get_next_visible(zephyr_row) {
return zephyr_row.nextAll(':visible:first'); return zephyr_row.nextAll('tr.zephyr_row:visible:first');
} }
function get_prev_visible(zephyr_row) { function get_prev_visible(zephyr_row) {
return zephyr_row.prevAll(':visible:first'); return zephyr_row.prevAll('tr.zephyr_row:visible:first');
} }
function get_id(zephyr_row) { function get_id(zephyr_row) {
return zephyr_row.attr('id'); return zephyr_row.attr('zid');
} }
function get_zephyr(zephyr_id) { function get_zephyr(zephyr_id) {
return $("#" + zephyr_id); return $("table.focused_table [zid=" + zephyr_id + "]");
} }
function scroll_to_selected() { function scroll_to_selected() {
@ -265,11 +265,21 @@ function scroll_to_selected() {
main_div.scrollTop(get_zephyr(selected_zephyr_id).offset().top - main_div.height()/1.5); main_div.scrollTop(get_zephyr(selected_zephyr_id).offset().top - main_div.height()/1.5);
} }
function get_huddle_recipient(zephyr) {
var recipient, i;
recipient = '';
for (i = 0; i < zephyr.display_recipient.length; i++) {
recipient += zephyr.display_recipient[i].name + ', ';
}
return recipient;
}
function respond_to_zephyr() { function respond_to_zephyr() {
var parent, zephyr; var parent, zephyr;
var recipient, recipients; var recipient, recipients;
parent = get_zephyr(selected_zephyr_id); parent = get_zephyr(selected_zephyr_id);
zephyr = zephyr_dict[parent.attr('id')]; zephyr = zephyr_dict[parent.attr('zid')];
if (zephyr.type === 'class') { if (zephyr.type === 'class') {
$('#zephyr-type-tabs a[href="#class-message"]').tab('show'); $('#zephyr-type-tabs a[href="#class-message"]').tab('show');
@ -278,10 +288,7 @@ function respond_to_zephyr() {
show_compose('class', $("#new_zephyr")); show_compose('class', $("#new_zephyr"));
} else if (zephyr.type === 'huddle') { } else if (zephyr.type === 'huddle') {
$('#zephyr-type-tabs a[href="#personal-message"]').tab('show'); $('#zephyr-type-tabs a[href="#personal-message"]').tab('show');
recipient = ''; recipient = get_huddle_recipient(zephyr);
for (var i = 0; i < zephyr.display_recipient.length; i++) {
recipient += zephyr.display_recipient[i].name + ', ';
}
prepare_huddle(recipient); prepare_huddle(recipient);
} else if (zephyr.type === 'personal') { } else if (zephyr.type === 'personal') {
// Until we allow sending zephyrs based on multiple meaningful // Until we allow sending zephyrs based on multiple meaningful
@ -298,19 +305,19 @@ function respond_to_zephyr() {
} }
function update_pointer(zephyr) { function update_pointer(zephyr) {
var new_selected = get_id(zephyr);
if (new_selected == selected_zephyr_id)
return;
selected_zephyr_id = new_selected;
$('.selected_zephyr').removeClass('selected_zephyr'); $('.selected_zephyr').removeClass('selected_zephyr');
zephyr.addClass('selected_zephyr'); zephyr.addClass('selected_zephyr');
if (!narrowed) { var new_selected = get_id(zephyr);
if (!narrowed && new_selected !== selected_zephyr_id) {
// Narrowing is a temporary view on top of the home view and // Narrowing is a temporary view on top of the home view and
// doesn't permanently affect where you are. // doesn't permanently affect where you are.
//
// We also don't want to post if there's no effecive change.
$.post("update", { pointer: selected_zephyr_id }); $.post("update", { pointer: selected_zephyr_id });
} }
selected_zephyr_id = new_selected;
} }
function update_pointer_by_id(zephyr_id) { function update_pointer_by_id(zephyr_id) {
@ -338,8 +345,8 @@ function select_zephyr(zephyr_id) {
update_pointer(next_zephyr); update_pointer(next_zephyr);
if ((next_zephyr.offset().top < main_div.offset().top) || if ((next_zephyr.offset().top < main_div.offset().top) ||
(next_zephyr.offset().top + next_zephyr.height() > (next_zephyr.offset().top + next_zephyr.height() >
main_div.offset().top + main_div.height())) { main_div.offset().top + main_div.height())) {
scroll_to_selected(); scroll_to_selected();
} }
} }
@ -395,23 +402,22 @@ function process_hotkey(code) {
} }
function process_goto_hotkey(code) { function process_goto_hotkey(code) {
var zephyr = zephyr_dict[selected_zephyr_id];
switch (code) { switch (code) {
case 67: // 'c': narrow by recipient case 67: // 'c': narrow by recipient
parent = get_zephyr(selected_zephyr_id); if (zephyr.type === 'personal') {
zephyr_class = parent.find(".zephyr_class").text();
zephyr_huddle = parent.find(".zephyr_huddle_recipient").text();
if (zephyr_class == '' && zephyr_huddle == '') {
narrow_personals(); narrow_personals();
} else if (zephyr_class == '') { } else if (zephyr.type === 'huddle') {
narrow_huddle(); narrow_huddle();
} } else if (zephyr.type === 'class') {
else {
narrow_class(); narrow_class();
} }
break; break;
case 73: // 'i': narrow by instance case 73: // 'i': narrow by instance
narrow_instance(); if (zephyr.type === 'class') {
narrow_instance();
}
break; break;
case 80: // 'p': narrow to personals case 80: // 'p': narrow to personals
@ -471,14 +477,7 @@ function home_view(element) {
} }
var current_view_predicate = home_view; var current_view_predicate = home_view;
var current_view_original_message;
function apply_view(element) {
if (current_view_predicate(element)) {
element.show();
} else {
element.hide();
}
}
function prepare_huddle(recipients) { function prepare_huddle(recipients) {
// Used for both personals and huddles. // Used for both personals and huddles.
@ -487,55 +486,64 @@ function prepare_huddle(recipients) {
} }
function do_narrow(description, filter_function) { function do_narrow(description, original_message, filter_function) {
// Your pointer isn't changed when narrowed. // Your pointer isn't changed when narrowed.
narrowed = true; narrowed = true;
persistent_zephyr_id = selected_zephyr_id; persistent_zephyr_id = selected_zephyr_id;
// Hide the messages temporarily, so the browser doesn't waste time current_view_predicate = filter_function;
// incrementally recalculating the layout. current_view_original_message = original_message;
$("#main_div").hide();
// We want the zephyr on which the narrow happened to stay in the same place if possible. // We want the zephyr on which the narrow happened to stay in the same place if possible.
var old_top = $("#main_div").offset().top - get_zephyr(selected_zephyr_id).offset().top; var old_top = $("#main_div").offset().top - get_zephyr(selected_zephyr_id).offset().top;
current_view_predicate = filter_function; var parent;
get_all_zephyr_rows().each(function () {
apply_view($(this)); // Empty the filtered table right before we fill it again
$("#filtered_table").empty();
$.each(initial_zephyr_array, function (dummy, zephyr) {
if (filter_function(zephyr, original_message)) {
// It matched the filter, push it on to the array.
add_to_tables(zephyr, parent, $("#filtered_table"));
parent = zephyr;
}
}); });
// Show the new set of messages. // Show the new set of messages.
$("#main_div").show(); $("#filtered_table").addClass("focused_table");
select_zephyr(selected_zephyr_id);
scroll_to_selected();
$("#show_all_messages").removeAttr("disabled"); $("#show_all_messages").removeAttr("disabled");
$("#narrowbox").show(); $("#narrowbox").show();
$("#main_div").addClass('narrowed_view'); $("#main_div").addClass("narrowed_view");
$("#currently_narrowed_to").html(description); $("#currently_narrowed_to").html(description);
$("#table").removeClass("focused_table");
select_zephyr(selected_zephyr_id);
scroll_to_selected();
} }
function narrow_huddle() { function narrow_huddle() {
var recipients = get_zephyr(selected_zephyr_id).find(".zephyr_huddle_recipients_list").text(); var parent = zephyr_dict[selected_zephyr_id];
var message = "Group chats with " + recipients;
do_narrow(message, function (element) { var message = "Group chats with " + get_huddle_recipient(parent);
return (element.find(".zephyr_huddle_recipient").length > 0 &&
element.find(".zephyr_huddle_recipients_list").text() === recipients); do_narrow(message, parent, function (other, original) {
return get_huddle_recipient(other) === get_huddle_recipient(original);
}); });
} }
function narrow_all_personals() { function narrow_all_personals() {
// Narrow to all personals // Narrow to all personals
var message = "All huddles with you"; var message = "All huddles with you";
do_narrow(message, function (element) { do_narrow(message, undefined, function (other, original) {
return (element.find(".zephyr_personal_recipient").length > 0); return other.type === "personal" || other.type === "huddle";
}); });
} }
function narrow_personals() { function narrow_personals() {
// Narrow to personals with a specific user // Narrow to personals with a specific user
var target_zephyr = get_zephyr(selected_zephyr_id); var target_zephyr = get_zephyr(selected_zephyr_id);
var zephyr_obj = zephyr_dict[target_zephyr.attr('id')]; var zephyr_obj = zephyr_dict[target_zephyr.attr('zid')];
var other_party; var other_party;
if (zephyr_obj.display_recipient === username) { if (zephyr_obj.display_recipient === username) {
other_party = zephyr_obj.sender; other_party = zephyr_obj.sender;
@ -543,53 +551,56 @@ function narrow_personals() {
other_party = zephyr_obj.display_recipient; other_party = zephyr_obj.display_recipient;
} }
var message = "Huddles with " + other_party; var message = "Huddles with " + other_party;
do_narrow(message, function (element) {
var other_zephyr_obj = zephyr_dict[target_zephyr.attr('id')];
var recipient = element.find(".zephyr_personal_recipient");
var sender = element.find(".zephyr_sender");
return (recipient.length > 0) && do_narrow(message, zephyr_dict[selected_zephyr_id], function (other, original) {
(((other_zephyr_obj.display_recipient === zephyr_obj.display_recipient) && (other_zephyr_obj.sender === zephyr_obj.sender)) || return (other.type === 'personal') &&
((other_zephyr_obj.display_recipient === zephyr_obj.sender) && (other_zephyr_obj.sender === zephyr_obj.display_recipient))); (((other.display_recipient === original.display_recipient) && (other.sender === original.sender)) ||
((other.display_recipient === original.sender) && (other.sender === original.display_recipient)));
}); });
} }
function narrow_class() { function narrow_class() {
var parent = get_zephyr(selected_zephyr_id); var parent = zephyr_dict[selected_zephyr_id];
var zephyr_class = parent.find(".zephyr_class").text(); var message = "<span class='zephyr_class'>" + parent.display_recipient + "</span>";
var message = "<span class='zephyr_class'>" + zephyr_class + "</span>"; do_narrow(message, parent, function (other, original) {
do_narrow(message, function (element) { return (other.type === 'class' &&
return (element.find(".zephyr_class").length > 0 && original.display_recipient === other.display_recipient);
element.find(".zephyr_class").text() === zephyr_class);
}); });
} }
function narrow_instance() { function narrow_instance() {
var parent = get_zephyr(selected_zephyr_id); var parent = zephyr_dict[selected_zephyr_id];
var zephyr_class = parent.find(".zephyr_class").text(); var message = "<span class='zephyr_class'>" + parent.display_recipient
var zephyr_instance = parent.find(".zephyr_instance").text(); + "</span> | <span class='zephyr_instance'>" + parent.instance
var message = "<span class='zephyr_class'>" + zephyr_class + "</span>";
+ "</span> | <span class='zephyr_instance'>" + zephyr_instance + "</span>"; do_narrow(message, parent, function (other, original) {
do_narrow(message, function (element) { return (other.type === 'class' &&
return (element.find(".zephyr_class").length > 0 && original.display_recipient === other.display_recipient &&
element.find(".zephyr_class").text() === zephyr_class && original.instance === other.instance);
element.find(".zephyr_instance").text() === zephyr_instance);
}); });
} }
function show_all_messages() { function show_all_messages() {
if (!narrowed) {
return;
}
narrowed = false; narrowed = false;
current_view_predicate = home_view; current_view_predicate = home_view;
get_all_zephyr_rows().show(); current_view_original_message = undefined;
// Includes scrolling.
select_zephyr(persistent_zephyr_id);
$("#filtered_table").removeClass('focused_table');
$("#table").addClass('focused_table');
$("#narrowbox").hide(); $("#narrowbox").hide();
$("#main_div").removeClass('narrowed_view'); $("#main_div").removeClass('narrowed_view');
$("#show_all_messages").attr("disabled", "disabled"); $("#show_all_messages").attr("disabled", "disabled");
$("#currently_narrowed_to").html(""); $("#currently_narrowed_to").html("");
// Includes scrolling.
select_zephyr(persistent_zephyr_id);
scroll_to_selected();
} }
function update_autocomplete() { function update_autocomplete() {
@ -608,6 +619,34 @@ function update_autocomplete() {
}); });
} }
function add_to_tables(zephyr, parent, table) {
if (parent !== undefined &&
zephyr.type === parent.type && (
(zephyr.is_huddle && parent.name === zephyr.name) ||
(zephyr.is_personal && parent.display_recipient === zephyr.display_recipient) ||
(zephyr.is_class && parent.display_recipient === zephyr.display_recipient &&
parent.instance === zephyr.instance)
)) {
zephyr.include_recipient = false;
} else {
zephyr.include_recipient = true;
// add a space to the table
table.append($('<tr />').append($('<td />')).append($('<td />')).append($('<td />').html('<br/>').addClass('bookend')));
}
if (parent !== undefined && !zephyr.include_recipient && zephyr.sender === parent.sender) {
zephyr.include_sender = false;
table.children('tr:last-child td:last-child').addClass("collapsed_parent");
} else {
zephyr.include_sender = true;
}
var new_tr = ich.zephyr(zephyr);
table.append(new_tr);
register_huddle_onclick(new_tr, zephyr.sender);
}
function add_message(index, zephyr) { function add_message(index, zephyr) {
last_received = Math.max(last_received, zephyr.id); last_received = Math.max(last_received, zephyr.id);
@ -639,15 +678,22 @@ function add_message(index, zephyr) {
} }
var time = new Date(zephyr.timestamp * 1000); var time = new Date(zephyr.timestamp * 1000);
var two_digits = function (x) { return ('0' + x).slice(-2); } var two_digits = function (x) { return ('0' + x).slice(-2); };
zephyr.timestr = two_digits(time.getHours()) zephyr.timestr = two_digits(time.getHours())
+ ':' + two_digits(time.getMinutes()); + ':' + two_digits(time.getMinutes());
zephyr.full_date_str = time.toLocaleString(); zephyr.full_date_str = time.toLocaleString();
var new_tr = ich.zephyr(zephyr) var parent = zephyr_dict[$('#table tr:last-child').attr('zid')];
$('#table').append(new_tr);
register_huddle_onclick(new_tr, zephyr.sender); add_to_tables(zephyr, parent, $('#table'));
apply_view(new_tr);
// now lets see if the filter applies to the message
var parent_filtered = zephyr_dict[$('#filtered_table tr:last-child').attr('zid')];
if (current_view_predicate(zephyr, current_view_original_message)) {
add_to_tables(zephyr, parent_filtered, $('#filtered_table'));
}
// save the zephyr object, with computed values for various is_* // save the zephyr object, with computed values for various is_*
zephyr_dict[zephyr.id] = zephyr; zephyr_dict[zephyr.id] = zephyr;
@ -678,7 +724,11 @@ function get_updates_longpoll() {
$('#connection-error').hide(); $('#connection-error').hide();
if (data && data.zephyrs) { if (data && data.zephyrs) {
$.each(data.zephyrs, add_message); $.each(data.zephyrs, function (dummy, zephyr) {
add_message(zephyr);
zephyr_dict[zephyr.id] = zephyr;
initial_zephyr_array.push(zephyr);
});
} }
setTimeout(get_updates_longpoll, 0); setTimeout(get_updates_longpoll, 0);
}, },

View File

@ -114,6 +114,11 @@ td.zephyr_recipient {
table.zephyr_table { table.zephyr_table {
table-layout: fixed; table-layout: fixed;
margin-left: auto; margin-left: auto;
display: none;
}
table.focused_table {
display: table;
} }
.zephyr_content { .zephyr_content {
@ -138,6 +143,15 @@ td.messagebox {
border: 1px solid gray; border: 1px solid gray;
} }
td.collapsed_child {
padding-top: 0px;
border-top: 1px; solid white
}
td.collapsed_parent {
border-bottom-width: 0px;
}
img.profile_picture { img.profile_picture {
display: block; display: block;
float: left; float: left;