I've made a Pomodoro Timer application. All it does is countdown from a time in minutes given by the user to 0:00. It does this first for a session time, and then switches to a break timer and continuously loops like this until the application is paused or closed.
The time can be adjusted by clicking on a '+' or '-' beside the time.
In doing this project I wanted to learn how i could better organize my code as far as separation of concerns goes. Therefore I'm primarily looking for feedback as to how the the pieces of code could be better organized. I split it up between a model for the data and functions that change the data and a view to draw the application and set up event listeners.
Here is the Javascript :
'use strict';
$(function() {
var model = (function() {
var data = {
minutes : null,
temp : null,
tempBreak : null,
seconds : null,
timer : {session : true, break : false},
active : null // check to see if a timer interval is already set.
};
var timer;
function changeTime() {
data.seconds = (data.seconds > 0) ? data.seconds - 1 : 59;
data.minutes = (data.minutes > 0 && data.seconds === 59) ? data.minutes - 1 : data.minutes;
if (data.seconds === 0 && data.minutes === 0) {
changeTimer();
}
view.render();
}
function changeTimer() {
data.timer['session'] = !data.timer['session'];
data.timer['break'] = !data.timer['break'];
model.resetTimer();
}
return {
init : function() {
data.minutes = 25;
data.temp = data.minutes;
data.tempBreak = 5;
data.seconds = 0;
data.timer['session'] = true;
data.timer['break'] = false;
data.active = false;
},
incrementMinutes : function() {
if (!data.active) {
if (data.timer['session']) {
data.temp++;
data.minutes = data.temp;
} else if (data.timer['break']) {
data.tempBreak++;
data.minutes = data.tempBreak;
}
model.resetTimer();
}
view.render();
},
decrementMinutes : function() {
if (!data.active) {
if (data.timer['session']) {
data.temp = (data.temp > 0) ? data.temp - 1 : 0;
data.minutes = data.temp;
} else if (data.timer['break']) {
data.tempBreak = (data.tempBreak > 0) ? data.tempBreak - 1 : 0;
data.minutes = data.tempBreak;
}
model.resetTimer();
}
view.render();
},
getMinutes : function() {
return data.minutes;
},
getSeconds : function() {
return data.seconds;
},
switchToSession : function() {
if (!data.active) {
data.timer['session'] = true;
data.timer['break'] = false;
model.resetTimer();
view.render();
}
},
switchToBreak : function() {
if (!data.active) {
data.timer['session'] = false;
data.timer['break'] = true;
model.resetTimer();
view.render();
}
},
getTimerType : function() {
return (data.timer['session']) ? 'Session' : 'Break';
},
startTimer : function() {
data.active = !data.active;
if (data.active){
timer = setInterval(function() {
changeTime();
}, 1000);
} else {
model.pauseTimer();
}
},
pauseTimer : function() {
data.active = false;
clearInterval(timer);
},
resetTimer : function() {
data.minutes = (data.timer['session']) ? data.temp : data.tempBreak;
data.seconds = 0;
view.render();
}
};
})();
var view = (function() {
// Cache the DOM
var sessionCheck = document.getElementById('session');
var breakCheck = document.getElementById('break');
var timerHeading = document.getElementById('timerType');
var up = document.getElementById('up');
var down = document.getElementById('down');
var minutes = document.getElementById('minutes');
var seconds = document.getElementById('seconds');
var start = document.getElementById('start');
var pause = document.getElementById('pause');
var reset = document.getElementById('reset');
// Bind events
sessionCheck.addEventListener('mouseup', model.switchToSession);
breakCheck.addEventListener('mouseup', model.switchToBreak);
up.addEventListener('mouseup', model.incrementMinutes);
down.addEventListener('mouseup', model.decrementMinutes);
start.addEventListener('mouseup', model.startTimer);
pause.addEventListener('mouseup', model.pauseTimer);
reset.addEventListener('mouseup', model.resetTimer);
var render = function() {
minutes.innerHTML = model.getMinutes();
seconds.innerHTML = (model.getSeconds() > 9) ? model.getSeconds() : '0' + model.getSeconds();
timerHeading.innerHTML = model.getTimerType();
}
return {
render : render
};
})();
model.init();
view.render();
});
Here is the Pen: http://codepen.io/rfdeveloper/pen/vNXJLQ?editors=001