You can't change the timeout of an ongoing setTimeout - instead, you'll have to explicitly clearTimeout on the existing timeout, then call setTimeout again with the new duration. For this, you'll need a persistent variable that notes when the next timeout (if any) is due to trigger, and 0 otherwise - when the second listener triggers, check the difference between that variable and Date.now() to figure out how long the new timeout needs to last:
const removeFn = () => {
$controlOpacity.removeClass('open');
triggerAt = 0;
};
let timeout;
let triggerAt = 0;
$controlOpacity.on('click','BUTTON', function() {
$controlOpacity.toggleClass('open');
timeout = setTimeout(removeFn, 5000);
// Set triggerAt so we can determine how long the timeout has left later
triggerAt = Date.now() + 5000;
});
$('INPUT', $controlOpacity).change(function() {
// Clear the existing timeout, if it exists
clearTimeout(timeout);
// If no timeout is running, return early
if (!triggerAt) return;
// Figure out how much time was remaining on the existing timeout
const remaining = triggerAt - Date.now();
// Set the new timeout for 5000 ms plus however long the old timeout had left
timeout = setTimeout(removeFn, remaining + 5000);
triggerAt += 5000;
});
ES5 version:
var removeFn = function() {
$controlOpacity.removeClass('open');
triggerAt = 0;
};
var timeout;
var triggerAt = 0;
$controlOpacity.on('click','BUTTON', function() {
$controlOpacity.toggleClass('open');
timeout = setTimeout(removeFn, 5000);
// Set triggerAt so we can determine how long the timeout has left later
triggerAt = Date.now() + 5000;
});
$('INPUT', $controlOpacity).change(function() {
// Clear the existing timeout, if it exists
clearTimeout(timeout);
// If no timeout is running, return early
if (!triggerAt) return;
// Figure out how much time was remaining on the existing timeout
var remaining = triggerAt - Date.now();
// Set the new timeout for 5000 ms plus however long the old timeout had left
timeout = setTimeout(removeFn, remaining + 5000);
triggerAt += 5000;
});
As your question asks, this extends the existing timeout by 5000 ms - an alternative, which simply clears the existing timeout and sets a new timeout for 5000 ms in the future, will take less code, since you'll only have to keep track of whether the timeout is ongoing, and not how much time it has left:
const removeFn = () => {
$controlOpacity.removeClass('open');
running = false;
};
let timeout;
let running = false;
$controlOpacity.on('click','BUTTON', function() {
$controlOpacity.toggleClass('open');
timeout = setTimeout(removeFn, 5000);
running = true;
});
$('INPUT', $controlOpacity).change(function() {
clearTimeout(timeout);
if (!running) return;
timeout = setTimeout(removeFn, 5000);
});
ES5 version:
var removeFn = function() {
$controlOpacity.removeClass('open');
running = false;
};
var timeout;
var running = false;
$controlOpacity.on('click','BUTTON', function() {
$controlOpacity.toggleClass('open');
timeout = setTimeout(removeFn, 5000);
running = true;
});
$('INPUT', $controlOpacity).change(function() {
clearTimeout(timeout);
if (!running) return;
timeout = setTimeout(removeFn, 5000);
});
If it's impossible to trigger the change event when the open class is not there, then it gets even easier, since there won't be any need to check whether the timeout is running or not:
const removeFn = () => {
$controlOpacity.removeClass('open');
};
let timeout;
$controlOpacity.on('click','BUTTON', function() {
$controlOpacity.toggleClass('open');
timeout = setTimeout(removeFn, 5000);
});
$('INPUT', $controlOpacity).change(function() {
clearTimeout(timeout);
timeout = setTimeout(removeFn, 5000);
});
ES5 version:
var removeFn = function() {
$controlOpacity.removeClass('open');
};
var timeout;
$controlOpacity.on('click','BUTTON', function() {
$controlOpacity.toggleClass('open');
timeout = setTimeout(removeFn, 5000);
});
$('INPUT', $controlOpacity).change(function() {
clearTimeout(timeout);
timeout = setTimeout(removeFn, 5000);
});