mirror of https://github.com/zulip/zulip.git
Make the back button work when narrowed
(imported from commit be922b06e7b53ec21751e67a490bb518333c3e6c)
This commit is contained in:
parent
a2f26f1106
commit
db6f03d46d
|
@ -55,6 +55,7 @@
|
|||
<script type="text/javascript" src="{{ static_hidden }}js/composebox_typeahead.js"></script>
|
||||
<script type="text/javascript" src="{{ static_hidden }}js/hotkey.js"></script>
|
||||
<script type="text/javascript" src="{{ static_hidden }}js/notifications.js"></script>
|
||||
<script type="text/javascript" src="{{ static_hidden }}js/hashchange.js"></script>
|
||||
<script type="text/javascript" src="{{ static_hidden }}js/zephyr.js"></script>
|
||||
|
||||
{% if debug %}
|
||||
|
|
|
@ -45,6 +45,9 @@ var globals =
|
|||
// notifications.js
|
||||
+ ' notifications'
|
||||
|
||||
// hashchange.js
|
||||
+ ' hashchange'
|
||||
|
||||
// ui.js
|
||||
+ ' ui'
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
../../../static/js/hashchange.js
|
|
@ -0,0 +1,38 @@
|
|||
var hashchange = (function () {
|
||||
|
||||
var exports = {};
|
||||
|
||||
var expected_hash = false;
|
||||
|
||||
exports.changehash = function (newhash) {
|
||||
expected_hash = newhash;
|
||||
window.location.hash = newhash;
|
||||
};
|
||||
|
||||
function hashchanged() {
|
||||
// If window.location.hash changed because our app explicitly
|
||||
// changed it, then we don't need to do anything.
|
||||
// (This function only neds to jump into action if it changed
|
||||
// because e.g. the back button was pressed by the user)
|
||||
if (window.location.hash === expected_hash) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hash = window.location.hash.split("/");
|
||||
if (hash[0] === "#narrow") {
|
||||
narrow.hashchanged(hash);
|
||||
ui.update_floating_recipient_bar();
|
||||
}
|
||||
else if (narrow.active()) {
|
||||
narrow.show_all_messages();
|
||||
ui.update_floating_recipient_bar();
|
||||
}
|
||||
}
|
||||
|
||||
exports.initialize = function () {
|
||||
window.onhashchange = hashchanged;
|
||||
};
|
||||
|
||||
return exports;
|
||||
|
||||
}());
|
|
@ -44,6 +44,40 @@ exports.data = function () {
|
|||
return narrowdata;
|
||||
};
|
||||
|
||||
exports.hashchanged = function (hash) {
|
||||
var full_names, decoded, emails;
|
||||
|
||||
if (hash[1] === "all_private_messages") {
|
||||
exports.all_private_messages();
|
||||
}
|
||||
else if (hash[1] === "stream" && hash[3] === "subject") {
|
||||
exports.by_stream_and_subject_names(decodeURIComponent(hash[2]),
|
||||
decodeURIComponent(hash[4]));
|
||||
}
|
||||
else if (hash[1] === "stream") {
|
||||
exports.by_stream_name(decodeURIComponent(hash[2]));
|
||||
}
|
||||
else if (hash[1] === "private_messages") {
|
||||
decoded = decodeURIComponent(hash[2]);
|
||||
emails = decoded.split(", ");
|
||||
|
||||
$.each(emails, function (index, email) {
|
||||
$.each(people_list, function (index, person) {
|
||||
if (person.email === email) {
|
||||
if (full_names === undefined) {
|
||||
full_names = person.full_name;
|
||||
}
|
||||
else {
|
||||
full_names += ", " + person.full_name;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
exports.by_private_message_group(full_names, decoded);
|
||||
}
|
||||
};
|
||||
|
||||
function do_narrow(new_narrow, bar, time_travel, new_filter) {
|
||||
var was_narrowed = exports.active();
|
||||
|
||||
|
@ -120,6 +154,8 @@ exports.target = function (id) {
|
|||
};
|
||||
|
||||
exports.all_private_messages = function () {
|
||||
hashchange.changehash("#narrow/all_private_messages");
|
||||
|
||||
var new_narrow = {type: "all_private_messages"};
|
||||
var bar = {icon: 'user', description: 'You and anyone else'};
|
||||
do_narrow(new_narrow, bar, false, function (other) {
|
||||
|
@ -135,23 +171,33 @@ exports.by_subject = function () {
|
|||
exports.by_recipient();
|
||||
return;
|
||||
}
|
||||
exports.by_stream_and_subject_names(original.display_recipient,
|
||||
original.subject);
|
||||
};
|
||||
|
||||
var new_narrow = {type: "subject", recipient_id: original.recipient_id,
|
||||
subject: original.subject};
|
||||
exports.by_stream_and_subject_names = function (stream, subject) {
|
||||
hashchange.changehash("#narrow/stream/" +
|
||||
encodeURIComponent(stream) +
|
||||
"/subject/" +
|
||||
encodeURIComponent(subject));
|
||||
|
||||
var new_narrow = {type: "subject", stream: stream, subject: subject};
|
||||
var bar = {
|
||||
icon: 'bullhorn',
|
||||
description: original.display_recipient,
|
||||
subject: original.subject
|
||||
icon: 'bullhorn',
|
||||
description: stream,
|
||||
subject: subject
|
||||
};
|
||||
do_narrow(new_narrow, bar, false, function (other) {
|
||||
return ((other.type === 'stream') &&
|
||||
same_stream_and_subject(original, other));
|
||||
(other.display_recipient === stream &&
|
||||
other.subject.toLowerCase() === subject.toLowerCase()));
|
||||
});
|
||||
};
|
||||
|
||||
//TODO: There's probably some room to unify this code
|
||||
// with the hotkey-narrowing code below.
|
||||
exports.by_stream_name = function (name) {
|
||||
hashchange.changehash("#narrow/stream/" +
|
||||
encodeURIComponent(name));
|
||||
|
||||
var new_narrow = {type: "stream", stream: name};
|
||||
var bar = {icon: 'bullhorn', description: name};
|
||||
do_narrow(new_narrow, bar, false, function (other) {
|
||||
|
@ -160,43 +206,38 @@ exports.by_stream_name = function (name) {
|
|||
});
|
||||
};
|
||||
|
||||
exports.by_private_message_partner = function (their_name, their_email) {
|
||||
var new_narrow = {type: "private", one_on_one_email: their_email};
|
||||
var bar = {icon: 'user', description: "You and " + their_name};
|
||||
exports.by_private_message_group = function (names, emails) {
|
||||
hashchange.changehash("#narrow/private_messages/" +
|
||||
encodeURIComponent(emails));
|
||||
|
||||
var new_narrow = {type: "private", emails: emails.split(", ")};
|
||||
var bar = {icon: 'user', description: "You and " + names};
|
||||
var my_email = email;
|
||||
do_narrow(new_narrow, bar, false, function (other) {
|
||||
return (other.type === 'private' &&
|
||||
get_private_message_recipient(other, 'email') === their_email);
|
||||
other.reply_to === emails);
|
||||
});
|
||||
};
|
||||
|
||||
// Called for the 'narrow by stream' hotkey.
|
||||
exports.by_recipient = function () {
|
||||
var message = message_dict[target_id];
|
||||
var bar;
|
||||
var new_narrow;
|
||||
var bar, new_narrow, emails;
|
||||
switch (message.type) {
|
||||
case 'private':
|
||||
new_narrow = {type: "private", recipient_id: message.recipient_id};
|
||||
bar = {icon: 'user', description: "You and " + message.display_reply_to};
|
||||
do_narrow(new_narrow, bar, false, function (other) {
|
||||
return (other.type === "private" &&
|
||||
other.reply_to === message.reply_to);
|
||||
});
|
||||
exports.by_private_message_group(message.display_reply_to,
|
||||
message.reply_to);
|
||||
break;
|
||||
|
||||
case 'stream':
|
||||
new_narrow = {type: "stream", recipient_id: message.recipient_id};
|
||||
bar = {icon: 'bullhorn', description: message.display_recipient};
|
||||
do_narrow(new_narrow, bar, false, function (other) {
|
||||
return (other.type === 'stream' &&
|
||||
message.recipient_id === other.recipient_id);
|
||||
});
|
||||
exports.by_stream_name(message.display_recipient);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
exports.by_search_term = function (term) {
|
||||
hashchange.changehash("#narrow/searchterm/" + encodeURIComponent(term));
|
||||
|
||||
var new_narrow = {type: "searchterm", searchterm: term, allow_collapse: false};
|
||||
var bar = {icon: 'search', description: 'Messages containing "' + term + '"'};
|
||||
var term_lowercase = term.toLowerCase();
|
||||
|
@ -208,6 +249,8 @@ exports.by_search_term = function (term) {
|
|||
};
|
||||
|
||||
exports.show_all_messages = function () {
|
||||
hashchange.changehash("");
|
||||
|
||||
if (!narrowdata) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ function narrow_or_search_for_term(item) {
|
|||
// unnarrow, it'll leave the searchbox.
|
||||
return ""; // Keep the search box empty
|
||||
} else if (obj.action === "private_message") {
|
||||
narrow.by_private_message_partner(obj.query.full_name, obj.query.email);
|
||||
narrow.by_private_message_group(obj.query.full_name, obj.query.email);
|
||||
return "";
|
||||
} else if (obj.action === "search_narrow") {
|
||||
narrow.by_search_term(obj.query);
|
||||
|
|
|
@ -176,7 +176,7 @@ function hide_floating_recipient_bar() {
|
|||
}
|
||||
}
|
||||
|
||||
function update_floating_recipient_bar() {
|
||||
exports.update_floating_recipient_bar = function () {
|
||||
var top_statusbar = $("#top_statusbar");
|
||||
var top_statusbar_top = top_statusbar.offset().top;
|
||||
var top_statusbar_bottom = top_statusbar_top + top_statusbar.outerHeight();
|
||||
|
@ -239,7 +239,8 @@ function update_floating_recipient_bar() {
|
|||
}
|
||||
|
||||
replace_floating_recipient_bar(current_label);
|
||||
}
|
||||
};
|
||||
|
||||
function hack_for_floating_recipient_bar() {
|
||||
// So, as of this writing, Firefox respects visibility: collapse,
|
||||
// but WebKit does not (at least, my Chrome doesn't.) Instead it
|
||||
|
@ -406,7 +407,7 @@ $(function () {
|
|||
$(window).scroll($.throttle(50, function (e) {
|
||||
if ($('#home').hasClass('active')) {
|
||||
keep_pointer_in_view();
|
||||
update_floating_recipient_bar();
|
||||
exports.update_floating_recipient_bar();
|
||||
if (viewport.scrollTop() === 0 &&
|
||||
have_scrolled_away_from_top) {
|
||||
have_scrolled_away_from_top = false;
|
||||
|
@ -590,6 +591,7 @@ $(function () {
|
|||
composebox_typeahead.initialize();
|
||||
search.initialize();
|
||||
notifications.initialize();
|
||||
hashchange.initialize();
|
||||
|
||||
$("body").bind('click', function () {
|
||||
ui.hide_userinfo_popover();
|
||||
|
|
|
@ -643,12 +643,12 @@ class GetOldMessagesTest(AuthedTestCase):
|
|||
|
||||
def test_bad_narrow_one_on_one_email_content(self):
|
||||
"""
|
||||
If an invalid one_on_one_email is requested in get_old_messages, an
|
||||
If an invalid 'emails' is requested in get_old_messages, an
|
||||
error is returned.
|
||||
"""
|
||||
self.login("hamlet@humbughq.com")
|
||||
bad_stream_content = ("non-existent email", 0, [])
|
||||
self.exercise_bad_narrow_content("one_on_one_email", bad_stream_content)
|
||||
bad_stream_content = (["non-existent email"], "non-existent email", 0, [])
|
||||
self.exercise_bad_narrow_content("emails", bad_stream_content)
|
||||
|
||||
class DummyHandler(object):
|
||||
def __init__(self, assert_callback):
|
||||
|
|
|
@ -283,20 +283,28 @@ def get_old_messages_backend(request, anchor = POST(converter=to_non_negative_in
|
|||
recipient = Recipient.objects.get(type=Recipient.STREAM, type_id=stream.id)
|
||||
query = query.filter(recipient_id = recipient.id)
|
||||
|
||||
if 'one_on_one_email' in narrow:
|
||||
if 'emails' in narrow and (type(narrow['emails']) != type([]) or len(narrow['emails']) == 0):
|
||||
return json_error("Invalid emails %s" % (narrow['emails'],))
|
||||
elif 'emails' in narrow and len(narrow['emails']) == 1:
|
||||
query = query.filter(recipient__type=Recipient.PERSONAL)
|
||||
try:
|
||||
recipient_user = UserProfile.objects.get(user__email = narrow['one_on_one_email'])
|
||||
recipient_user = UserProfile.objects.get(user__email = narrow['emails'][0])
|
||||
except UserProfile.DoesNotExist:
|
||||
return json_error("Invalid one_on_one_email %s" % (narrow['one_on_one_email'],))
|
||||
return json_error("Invalid emails ['" + narrow['emails'][0] + "']")
|
||||
recipient = Recipient.objects.get(type=Recipient.PERSONAL, type_id=recipient_user.id)
|
||||
# If we are narrowed to personals with ourself, we want to search for personals where the user
|
||||
# with address "one_on_one_email" is the sender *and* the recipient, not personals where the user
|
||||
# with address "one_on_one_email is the sender *or* the recipient.
|
||||
if narrow['one_on_one_email'] == user_profile.user.email:
|
||||
query = query.filter(Q(sender__user__email=narrow['one_on_one_email']) & Q(recipient=recipient))
|
||||
# with the desired e-mail address is the sender *and* the recipient, not personals where the
|
||||
# user with the desired e-mail address is the sender *or* the recipient.
|
||||
if narrow['emails'][0] == user_profile.user.email:
|
||||
query = query.filter(Q(sender__user__email=narrow['emails'][0]) & Q(recipient=recipient))
|
||||
else:
|
||||
query = query.filter(Q(sender__user__email=narrow['one_on_one_email']) | Q(recipient=recipient))
|
||||
query = query.filter(Q(sender__user__email=narrow['emails'][0]) | Q(recipient=recipient))
|
||||
elif 'emails' in narrow:
|
||||
try:
|
||||
recipient = recipient_for_emails(narrow['emails'], False, user_profile, user_profile)
|
||||
except ValidationError, e:
|
||||
return json_error(e.messages[0])
|
||||
query = query.filter(recipient=recipient)
|
||||
elif 'type' in narrow and (narrow['type'] == "private" or narrow['type'] == "all_private_messages"):
|
||||
query = query.filter(Q(recipient__type=Recipient.PERSONAL) | Q(recipient__type=Recipient.HUDDLE))
|
||||
|
||||
|
@ -611,6 +619,32 @@ def create_mirrored_message_users(request, user_profile, recipients):
|
|||
sender = UserProfile.objects.get(user__email=sender_email)
|
||||
return (True, sender)
|
||||
|
||||
def recipient_for_emails(emails, not_forged_zephyr_mirror, user_profile, sender):
|
||||
recipient_profile_ids = set()
|
||||
for email in emails:
|
||||
try:
|
||||
recipient_profile_ids.add(UserProfile.objects.get(user__email__iexact=email).id)
|
||||
except UserProfile.DoesNotExist:
|
||||
raise ValidationError("Invalid email '%s'" % (email,))
|
||||
|
||||
if not_forged_zephyr_mirror and user_profile.id not in recipient_profile_ids:
|
||||
raise ValidationError("User not authorized for this query")
|
||||
|
||||
# If the private message is just between the sender and
|
||||
# another person, force it to be a personal internally
|
||||
if (len(recipient_profile_ids) == 2
|
||||
and sender.id in recipient_profile_ids):
|
||||
recipient_profile_ids.remove(sender.id)
|
||||
|
||||
if len(recipient_profile_ids) > 1:
|
||||
# Make sure the sender is included in huddle messages
|
||||
recipient_profile_ids.add(sender.id)
|
||||
huddle = get_huddle(list(recipient_profile_ids))
|
||||
return Recipient.objects.get(type_id=huddle.id, type=Recipient.HUDDLE)
|
||||
else:
|
||||
return Recipient.objects.get(type_id=list(recipient_profile_ids)[0],
|
||||
type=Recipient.PERSONAL)
|
||||
|
||||
# We do not @require_login for send_message_backend, since it is used
|
||||
# both from the API and the web service. Code calling
|
||||
# send_message_backend should either check the API key or check that
|
||||
|
@ -683,31 +717,11 @@ def send_message_backend(request, user_profile, client,
|
|||
return json_error("Stream does not exist")
|
||||
recipient = Recipient.objects.get(type_id=stream.id, type=Recipient.STREAM)
|
||||
elif message_type_name == 'private':
|
||||
recipient_profile_ids = set()
|
||||
for email in message_to:
|
||||
try:
|
||||
recipient_profile_ids.add(UserProfile.objects.get(user__email__iexact=email).id)
|
||||
except UserProfile.DoesNotExist:
|
||||
return json_error("Invalid email '%s'" % (email,))
|
||||
|
||||
if client.name == "zephyr_mirror":
|
||||
if user_profile.id not in recipient_profile_ids and not forged:
|
||||
return json_error("User not authorized for this query")
|
||||
|
||||
# If the private message is just between the sender and
|
||||
# another person, force it to be a personal internally
|
||||
if (len(recipient_profile_ids) == 2
|
||||
and sender.id in recipient_profile_ids):
|
||||
recipient_profile_ids.remove(sender.id)
|
||||
|
||||
if len(recipient_profile_ids) > 1:
|
||||
# Make sure the sender is included in huddle messages
|
||||
recipient_profile_ids.add(sender.id)
|
||||
huddle = get_huddle(list(recipient_profile_ids))
|
||||
recipient = Recipient.objects.get(type_id=huddle.id, type=Recipient.HUDDLE)
|
||||
else:
|
||||
recipient = Recipient.objects.get(type_id=list(recipient_profile_ids)[0],
|
||||
type=Recipient.PERSONAL)
|
||||
not_forged_zephyr_mirror = client and client.name == "zephyr_mirror" and not forged
|
||||
try:
|
||||
recipient = recipient_for_emails(message_to, not_forged_zephyr_mirror, user_profile, sender)
|
||||
except ValidationError, e:
|
||||
return json_error(e.messages[0])
|
||||
else:
|
||||
return json_error("Invalid message type")
|
||||
|
||||
|
|
Loading…
Reference in New Issue