Files
zulip/zephyr/static/js/hashchange.js
Tim Abbott 55f606b417 Fix scrolling bug when unnarrowing after receiving a message.
What was happening is that if you un-narrowed immediately after
receiving a message (e.g. because you just sent it), the autoscroll
animation from the zfilt table would still be running after you return
to the home view, resulting in the viewport being scrolled to an
apparently random point in the home view (even though the pointer was
still in the right place).

This cancels the autoscroll animations whenever you do one of:
(1) hashchange (e.g. to go to the settings page)
(2) select a message (covers narrowing/unnarrowing as well as keyboard hotkeys)
(3) mousewheel scroll
since those are basically the cases where we set the viewport
scrolltop directly.

Arguably this should instead be something where we somehow detect
which scroll events are triggered by what and cancel for any scroll
event not from the animation or rererendering, but that seems hard.

(imported from commit f776021303404c87b36241c733b3d1bcb083163b)
2013-04-10 11:02:32 -04:00

126 lines
3.5 KiB
JavaScript

var hashchange = (function () {
var exports = {};
var expected_hash = false;
var changing_hash = false;
// Some browsers zealously URI-decode the contents of
// window.location.hash. So we hide our URI-encoding
// by replacing % with . (like MediaWiki).
function encodeHashComponent(str) {
return encodeURIComponent(str)
.replace(/\./g, '%2E')
.replace(/%/g, '.');
}
function decodeHashComponent(str) {
return decodeURIComponent(str.replace(/\./g, '%'));
}
exports.changehash = function (newhash) {
if (changing_hash) {
return;
}
$(document).trigger($.Event('hashchange'));
expected_hash = newhash;
// Some browsers reset scrollTop when changing the hash to "",
// so we save and restore it.
// http://stackoverflow.com/questions/4715073/window-location-hash-prevent-scrolling-to-the-top
var scrolltop = viewport.scrollTop();
window.location.hash = newhash;
util.reset_favicon();
if (newhash === "" || newhash === "#") {
viewport.scrollTop(scrolltop);
}
};
exports.save_narrow = function (operators) {
if (changing_hash) {
return;
}
if (operators === undefined) {
exports.changehash('#');
} else {
var new_hash = '#narrow';
$.each(operators, function (idx, elem) {
new_hash += '/' + encodeHashComponent(elem[0])
+ '/' + encodeHashComponent(elem[1]);
});
exports.changehash(new_hash);
}
};
function parse_narrow(hash) {
var i, operators = [];
for (i=1; i<hash.length; i+=2) {
// We don't construct URLs with an odd number of components,
// but the user might write one.
var operator = decodeHashComponent(hash[i]);
var operand = decodeHashComponent(hash[i+1] || '');
operators.push([operator, operand]);
}
narrow.activate(operators, {
select_first_unread: true,
change_hash: false // already set
});
}
// Returns true if this function performed a narrow
function do_hashchange() {
// 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 false;
}
// NB: In Firefox, window.location.hash is URI-decoded.
// Even if the URL bar says #%41%42%43%44, the value here will
// be #ABCD.
var hash = window.location.hash.split("/");
switch (hash[0]) {
case "#narrow":
ui.change_tab_to("#home");
parse_narrow(hash);
ui.update_floating_recipient_bar();
return true;
case "":
case "#":
ui.change_tab_to("#home");
narrow.deactivate();
ui.update_floating_recipient_bar();
break;
case "#subscriptions":
ui.change_tab_to("#subscriptions");
break;
case "#settings":
ui.change_tab_to("#settings");
break;
}
return false;
}
function hashchanged() {
changing_hash = true;
$(document).trigger($.Event('hashchange.zephyr'));
var ret = do_hashchange();
changing_hash = false;
return ret;
}
exports.initialize = function () {
// jQuery doesn't have a hashchange event, so we manually wrap
// our event handler
window.onhashchange = blueslip.wrap_function(hashchanged);
if (hashchanged()) {
load_more_messages(current_msg_list);
}
};
return exports;
}());