Countdown Timer - reactive data
<div id="app"></div>
<script>
var duration = 5;
var timer;
var handler = function (instance) {
return {
get: function (obj, prop) {
if (['[object Object]','[object Array]'].indexOf(Object.prototype.toString.call(obj[prop])) > -1) {
return new Proxy(obj[prop], handler(instance));
}
return obj[prop];
instance.render();
},
set: function (obj, prop, value) {
obj[prop] = value;
instance.render();
return true;
},
deleteProperty: function (obj, prop) {
delete obj[prop];
instance.render();
return true;
}
};
};
var Rue = function (selector, options) {
var _this = this;
_this.elem = document.querySelector(selector);
var _data = new Proxy(options.data, handler(this));
_this.template = options.template;
Object.defineProperty(this, 'data', {
get: function () {
return _data;
},
set: function (data) {
_data = new Proxy(data, handler(_this));
_this.render();
return true;
}
});
}
Rue.prototype.render = function () {
this.elem.innerHTML = this.template(this.data);
};
var stopTimer = function () {
clearInterval(timer);
};
var countdown = function () {
app.data.time--;
if (app.data.time < 1) {
stopTimer();
}
};
var clickHandler = function (event) {
startTimer(event);
pauseTimer(event);
restartTimer(event);
};
var startTimer = function (event) {
if (!event.target.hasAttribute('data-start-timer')) return;
if (app.data.time < 1) {
restartTimer();
return;
}
app.data.paused = false;
stopTimer();
timer = setInterval(countdown, 1000);
};
var pauseTimer = function (event) {
if (!event.target.hasAttribute('data-pause-timer')) return;
stopTimer();
app.data.paused = true;
};
var restartTimer = function (event) {
if (!event.target.hasAttribute('data-restart-timer')) return;
stopTimer();
app.data.time = duration;
app.data.paused = false;
timer = setInterval(countdown, 1000);
};
var app = new Rue('#app', {
data: {
time: duration,
paused: true
},
template: function (props) {
if (props.time < 1) {
return '⏰ <p><button data-restart-timer>Restart Timer</button></p>';
}
return getTimerHTML(props);
}
});
var getTimerHTML = function (props) {
var minutes = parseInt(props.time / 60, 10);
var seconds = props.time % 60;
var html =
minutes.toString() + ':' + seconds.toString().padStart(2, '0') +
'<p>' +
(props.paused ? '<button data-start-timer>Start</button>' : '<button data-pause-timer>Pause</button>') +
' <button data-restart-timer>Restart</button>' +
'</p>';
return html;
}
app.render();
document.addEventListener('click', clickHandler);
</script>