pad.libre-service.eu-etherpad/src/static/js/pad_automatic_reconnect.js

195 lines
5.6 KiB
JavaScript
Raw Normal View History

'use strict';
exports.showCountDownTimerToReconnectOnModal = ($modal, pad) => {
if (clientVars.automaticReconnectionTimeout && $modal.is('.with_reconnect_timer')) {
createCountDownElementsIfNecessary($modal);
2020-11-23 19:24:19 +01:00
const timer = createTimerForModal($modal, pad);
2020-11-23 19:24:19 +01:00
$modal.find('#cancelreconnect').one('click', () => {
timer.cancel();
disableAutomaticReconnection($modal);
});
enableAutomaticReconnection($modal);
}
2020-11-23 19:24:19 +01:00
};
const createCountDownElementsIfNecessary = ($modal) => {
2020-11-23 19:24:19 +01:00
const elementsDoNotExist = $modal.find('#cancelreconnect').length === 0;
if (elementsDoNotExist) {
2020-11-23 19:24:19 +01:00
const $defaultMessage = $modal.find('#defaulttext');
const $reconnectButton = $modal.find('#forcereconnect');
// create extra DOM elements, if they don't exist
const $reconnectTimerMessage =
$('<p>')
.addClass('reconnecttimer')
.append(
$('<span>')
.attr('data-l10n-id', 'pad.modals.reconnecttimer')
.text('Trying to reconnect in'))
.append(' ')
.append(
$('<span>')
.addClass('timetoexpire'));
const $cancelReconnect =
$('<button>')
.attr('id', 'cancelreconnect')
.attr('data-l10n-id', 'pad.modals.cancel')
.text('Cancel');
localize($reconnectTimerMessage);
localize($cancelReconnect);
$reconnectTimerMessage.insertAfter($defaultMessage);
$cancelReconnect.insertAfter($reconnectButton);
}
2020-11-23 19:24:19 +01:00
};
const localize = ($element) => {
html10n.translateElement(html10n.translations, $element.get(0));
};
const createTimerForModal = ($modal, pad) => {
const timeUntilReconnection =
clientVars.automaticReconnectionTimeout * reconnectionTries.nextTry();
2020-11-23 19:24:19 +01:00
const timer = new CountDownTimer(timeUntilReconnection);
2020-11-23 19:24:19 +01:00
timer.onTick((minutes, seconds) => {
updateCountDownTimerMessage($modal, minutes, seconds);
2020-11-23 19:24:19 +01:00
}).onExpire(() => {
const wasANetworkError = $modal.is('.disconnected');
if (wasANetworkError) {
// cannot simply reconnect, client is having issues to establish connection to server
2020-11-23 19:24:19 +01:00
waitUntilClientCanConnectToServerAndThen(() => { forceReconnection($modal); }, pad);
} else {
forceReconnection($modal);
}
}).start();
return timer;
2020-11-23 19:24:19 +01:00
};
const disableAutomaticReconnection = ($modal) => {
toggleAutomaticReconnectionOption($modal, true);
2020-11-23 19:24:19 +01:00
};
const enableAutomaticReconnection = ($modal) => {
toggleAutomaticReconnectionOption($modal, false);
2020-11-23 19:24:19 +01:00
};
const toggleAutomaticReconnectionOption = ($modal, disableAutomaticReconnect) => {
$modal.find('#cancelreconnect, .reconnecttimer').toggleClass('hidden', disableAutomaticReconnect);
$modal.find('#defaulttext').toggleClass('hidden', !disableAutomaticReconnect);
2020-11-23 19:24:19 +01:00
};
const waitUntilClientCanConnectToServerAndThen = (callback, pad) => {
whenConnectionIsRestablishedWithServer(callback, pad);
pad.socket.connect();
2020-11-23 19:24:19 +01:00
};
const whenConnectionIsRestablishedWithServer = (callback, pad) => {
// only add listener for the first try, don't need to add another listener
// on every unsuccessful try
if (reconnectionTries.counter === 1) {
pad.socket.once('connect', callback);
}
2020-11-23 19:24:19 +01:00
};
const forceReconnection = ($modal) => {
$modal.find('#forcereconnect').click();
2020-11-23 19:24:19 +01:00
};
const updateCountDownTimerMessage = ($modal, minutes, seconds) => {
2020-11-23 19:24:19 +01:00
minutes = minutes < 10 ? `0${minutes}` : minutes;
seconds = seconds < 10 ? `0${seconds}` : seconds;
2020-11-23 19:24:19 +01:00
$modal.find('.timetoexpire').text(`${minutes}:${seconds}`);
};
// store number of tries to reconnect to server, in order to increase time to wait
// until next try
const reconnectionTries = {
counter: 0,
2020-11-23 19:24:19 +01:00
nextTry() {
// double the time to try to reconnect on every time reconnection fails
2021-01-29 07:14:03 +01:00
const nextCounterFactor = 2 ** this.counter;
this.counter++;
return nextCounterFactor;
2020-11-23 19:24:19 +01:00
},
};
// Timer based on http://stackoverflow.com/a/20618517.
// duration: how many **seconds** until the timer ends
// granularity (optional): how many **milliseconds**
// between each 'tick' of timer. Default: 1000ms (1s)
const CountDownTimer = function (duration, granularity) {
2020-11-23 19:24:19 +01:00
this.duration = duration;
this.granularity = granularity || 1000;
2020-11-23 19:24:19 +01:00
this.running = false;
2020-11-23 19:24:19 +01:00
this.onTickCallbacks = [];
this.onExpireCallbacks = [];
2020-11-23 19:24:19 +01:00
};
2020-11-23 19:24:19 +01:00
CountDownTimer.prototype.start = function () {
if (this.running) {
return;
}
this.running = true;
2020-11-23 19:24:19 +01:00
const start = Date.now();
const that = this;
let diff;
const timer = () => {
diff = that.duration - Math.floor((Date.now() - start) / 1000);
if (diff > 0) {
that.timeoutId = setTimeout(timer, that.granularity);
that.tick(diff);
} else {
that.running = false;
that.tick(0);
that.expire();
}
};
timer();
};
2020-11-23 19:24:19 +01:00
CountDownTimer.prototype.tick = function (diff) {
const obj = CountDownTimer.parse(diff);
this.onTickCallbacks.forEach(function (callback) {
callback.call(this, obj.minutes, obj.seconds);
}, this);
2020-11-23 19:24:19 +01:00
};
CountDownTimer.prototype.expire = function () {
this.onExpireCallbacks.forEach(function (callback) {
callback.call(this);
}, this);
2020-11-23 19:24:19 +01:00
};
2020-11-23 19:24:19 +01:00
CountDownTimer.prototype.onTick = function (callback) {
if (typeof callback === 'function') {
this.onTickCallbacks.push(callback);
}
return this;
};
2020-11-23 19:24:19 +01:00
CountDownTimer.prototype.onExpire = function (callback) {
if (typeof callback === 'function') {
this.onExpireCallbacks.push(callback);
}
return this;
};
2020-11-23 19:24:19 +01:00
CountDownTimer.prototype.cancel = function () {
this.running = false;
clearTimeout(this.timeoutId);
return this;
};
CountDownTimer.parse = (seconds) => ({
minutes: (seconds / 60) | 0,
seconds: (seconds % 60) | 0,
});