mirror of https://github.com/zulip/zulip.git
Make the client reload the page when it detects a server restart
If the client is not composing a message, we can just force a page reload. However, if he is composing a message, we must preserve that message while still reloading as soon as possible. We take the following approach: if the client has not completed the composition after 5 minutes, do a compose-preserving reload (described below). If he sends the message before the timeout expires, reload the page after a successful send. If the send fails (not due to server timeout), however, we do a compose-perserving reload in case the error was due to the data format changing. If the send failed due to server timeout, we don't reload because the reload will probably also fail. In a compose-preserving reload, we redirect to an URI that has a fragment indicating we are doing a reload and containing all the necessary information for restoring the compose window to its previous state. On page load, we check the fragment to see if we just did a compose-preserving reload, and, if we did, we restore the compose window (or just try the send again in the case of send failure). The URI fragment looks like: (imported from commit af4eeb3930c24118e088057d4da456748fbd2229)
This commit is contained in:
parent
103bf321b4
commit
fab64fd7b0
|
@ -11,8 +11,9 @@ var globals =
|
||||||
|
|
||||||
// compose.js
|
// compose.js
|
||||||
+ ' show_compose hide_compose toggle_compose clear_compose_box compose_button'
|
+ ' show_compose hide_compose toggle_compose clear_compose_box compose_button'
|
||||||
+ ' composing_message compose_stream_name validate_message'
|
+ ' composing_message composing_stream_message compose_stream_name'
|
||||||
+ ' status_classes'
|
+ ' compose_stream_name compose_subject compose_recipient compose_message'
|
||||||
|
+ ' validate_message status_classes'
|
||||||
|
|
||||||
// dom_access.js
|
// dom_access.js
|
||||||
+ ' get_first_visible get_last_visible get_next_visible get_prev_visible'
|
+ ' get_first_visible get_last_visible get_next_visible get_prev_visible'
|
||||||
|
@ -45,6 +46,7 @@ var globals =
|
||||||
+ ' select_message select_message_by_id'
|
+ ' select_message select_message_by_id'
|
||||||
+ ' scroll_to_selected select_and_show_by_id'
|
+ ' scroll_to_selected select_and_show_by_id'
|
||||||
+ ' selected_message selected_message_id'
|
+ ' selected_message selected_message_id'
|
||||||
|
+ ' reload_app reload_app_preserving_compose'
|
||||||
+ ' at_top_of_viewport at_bottom_of_viewport'
|
+ ' at_top_of_viewport at_bottom_of_viewport'
|
||||||
+ ' viewport'
|
+ ' viewport'
|
||||||
;
|
;
|
||||||
|
|
|
@ -5,6 +5,7 @@ var people_hash = {};
|
||||||
|
|
||||||
var selected_message_class = 'selected_message';
|
var selected_message_class = 'selected_message';
|
||||||
var viewport = $(window);
|
var viewport = $(window);
|
||||||
|
var app_needs_reload = false;
|
||||||
|
|
||||||
$(function () {
|
$(function () {
|
||||||
var i;
|
var i;
|
||||||
|
@ -19,8 +20,17 @@ $(function () {
|
||||||
send_status.hide();
|
send_status.hide();
|
||||||
hide_compose();
|
hide_compose();
|
||||||
buttons.removeAttr('disabled');
|
buttons.removeAttr('disabled');
|
||||||
|
if (app_needs_reload) {
|
||||||
|
reload_app();
|
||||||
|
return;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error: function (xhr) {
|
error: function (xhr, error_type) {
|
||||||
|
if (error_type !== 'timeout' && app_needs_reload) {
|
||||||
|
// The error might be due to the server changing
|
||||||
|
reload_app_preserving_compose(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
var response = "Error sending message";
|
var response = "Error sending message";
|
||||||
if (xhr.status.toString().charAt(0) === "4") {
|
if (xhr.status.toString().charAt(0) === "4") {
|
||||||
// Only display the error response for 4XX, where we've crafted
|
// Only display the error response for 4XX, where we've crafted
|
||||||
|
@ -501,6 +511,75 @@ function add_messages(data) {
|
||||||
update_autocomplete();
|
update_autocomplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function reload_app() {
|
||||||
|
// If we can, reload the page immediately
|
||||||
|
if (! composing_message()) {
|
||||||
|
window.location.reload(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user is composing a message, wait until he's done or
|
||||||
|
// until a timeout expires
|
||||||
|
app_needs_reload = true;
|
||||||
|
setTimeout(function () { reload_app_preserving_compose(false); },
|
||||||
|
1000 * 60 * 5); // 5 minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
function reload_app_preserving_compose(send_after_reload) {
|
||||||
|
var url = "#reload:send_after_reload=" + Number(send_after_reload);
|
||||||
|
if (composing_stream_message()) {
|
||||||
|
url += "+msg_type=stream";
|
||||||
|
url += "+stream=" + encodeURIComponent(compose_stream_name());
|
||||||
|
url += "+subject=" + encodeURIComponent(compose_subject());
|
||||||
|
} else {
|
||||||
|
url += "+msg_type=huddle";
|
||||||
|
url += "+recipient=" + encodeURIComponent(compose_recipient());
|
||||||
|
}
|
||||||
|
url += "+msg="+ encodeURIComponent(compose_message());
|
||||||
|
|
||||||
|
window.location.replace(url);
|
||||||
|
window.location.reload(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're doing a compose-preserving reload. This must be
|
||||||
|
// done before the first call to get_updates
|
||||||
|
$(function () {
|
||||||
|
var location = window.location.toString();
|
||||||
|
window.location = '#';
|
||||||
|
var fragment = location.substring(location.indexOf('#') + 1);
|
||||||
|
if (fragment.search("reload:") !== 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment = fragment.replace(/^reload:/, "");
|
||||||
|
var keyvals = fragment.split("+");
|
||||||
|
var vars = {};
|
||||||
|
$.each(keyvals, function (idx, str) {
|
||||||
|
var pair = str.split("=");
|
||||||
|
vars[pair[0]] = decodeURIComponent(pair[1]);
|
||||||
|
});
|
||||||
|
|
||||||
|
var tab;
|
||||||
|
var send_now = parseInt(vars.send_after_reload, 10);
|
||||||
|
if (vars.msg_type === "stream") {
|
||||||
|
if (! send_now) {
|
||||||
|
show_compose("stream", $("#new_message_content"));
|
||||||
|
}
|
||||||
|
compose_stream_name(vars.stream);
|
||||||
|
compose_subject(vars.subject);
|
||||||
|
} else {
|
||||||
|
if (! send_now) {
|
||||||
|
show_compose("huddle", $("#new_message_content"));
|
||||||
|
}
|
||||||
|
show_compose("huddle", $("#new_message_content"));
|
||||||
|
compose_recipient(vars.recipient);
|
||||||
|
}
|
||||||
|
compose_message(vars.msg);
|
||||||
|
|
||||||
|
if (send_now) {
|
||||||
|
$("#compose form").ajaxSubmit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var get_updates_xhr;
|
var get_updates_xhr;
|
||||||
var get_updates_timeout;
|
var get_updates_timeout;
|
||||||
function get_updates() {
|
function get_updates() {
|
||||||
|
@ -514,6 +593,10 @@ function get_updates() {
|
||||||
received.failures = 0;
|
received.failures = 0;
|
||||||
$('#connection-error').hide();
|
$('#connection-error').hide();
|
||||||
|
|
||||||
|
if (data.server_generation > server_generation) {
|
||||||
|
reload_app();
|
||||||
|
}
|
||||||
|
|
||||||
add_messages(data);
|
add_messages(data);
|
||||||
get_updates_timeout = setTimeout(get_updates, 0);
|
get_updates_timeout = setTimeout(get_updates, 0);
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue