Adding Alarms to the Digital Clock

Adding Alarms to the Digital Clock

The Idea

To extend the digital clock with support for alarms, we need to add a few crucial pieces of functionality to the code from last week:
  • We need to have a way for people to set and edit alarms. This would require some kind of dialog with fields for setting the time of the alarm;
  • Every second, we will need to check whether an alarm should go off. If it should, we will play a small audio file and display a “Time’s up” dialog.
These features will require changes to the HTML, CSS and jQuery. Let’s begin!
Setting an Alarm
Setting an Alarm

The HTML

We will have two dialogs – one for setting/editing an alarm, and another that is displayed when an alarm goes off.

index.html

<div class="overlay">

    <div id="alarm-dialog">

        <h2>Set alarm after</h2>

        <label class="hours">
            Hours
            <input type="number" value="0" min="0" />
        </label>

        <label class="minutes">
            Minutes
            <input type="number" value="0" min="0" />
        </label>

        <label class="seconds">
            Seconds
            <input type="number" value="0" min="0" />
        </label>

        <div class="button-holder">
            <a id="alarm-set" class="button blue">Set</a>
            <a id="alarm-clear" class="button red">Clear</a>
        </div>

        <a class="close"></a>

    </div>

</div>

<div class="overlay">

    <div id="time-is-up">

        <h2>Time's up!</h2>

        <div class="button-holder">
            <a class="button blue">Close</a>
        </div>

    </div>

</div>
Both of these dialogs are hidden with CSS and are shown with the jQuery fadeIn() method when they are needed. Another thing worth noting is that the alarm dialog uses the HTML5 number input types with a min value of 0. Number inputs are very easy to validate with JavaScript (more about that in the next section) and they also bring up the number keyboard on mobile devices.
Next is the HTML5 audio element. It contains source tags with two different audio formats. The first is an mp3 version of the alarm sound, and the second ogg. The ogg format is only needed in Firefox, which doesn’t yet support mp3 playback due to licensing issues. Pretty much all other browsers which support HTML5 audio also support mp3.

index.html

<audio id="alarm-ring" preload>
    <source src="assets/audio/ticktac.mp3" type="audio/mpeg" />
    <source src="assets/audio/ticktac.ogg" type="audio/ogg" />
</audio>
The preload attribute tells the browser that these sound files should be downloaded ahead of time, which will make them immediately available once we decide to play them (otherwise there would be a delay the first time an alarm is played until they are downloaded). Playing the audio file is extremely simple thanks to JavaScript’s HTML5 audio API (more on that in the next fragment).

The jQuery

In this section of the tutorial, we will extend the jQuery code of the digital clock to support and play the alarms. I won’t be explaining the code we wrote last time, only the new additions.
The first thing we have to do is to define a number of variables, important for the functioning of the alarms:

assets/js/script.js

var dialog = $('#alarm-dialog').parent(),
    alarm_set = $('#alarm-set'),
    alarm_clear = $('#alarm-clear'),
    time_is_up = $('#time-is-up').parent();

// This will hold the number of seconds left
// until the alarm should go off
var alarm_counter = -1;
Next, we have to check whether there is an alarm pending on every tick of the update_time() function.
// Is there an alarm set?

if(alarm_counter > 0){

    // Decrement the counter with one second
    alarm_counter--;

    // Activate the alarm icon
    alarm.addClass('active');
}
else if(alarm_counter == 0){

    time_is_up.fadeIn();

    // Play the alarm sound. This will fail
    // in browsers which don't support HTML5 audio

    try{
        $('#alarm-ring')[0].play();
    }
    catch(e){}

    alarm_counter--;
    alarm.removeClass('active');
}
else{
    // The alarm has been cleared
    alarm.removeClass('active');
}
When the counter reaches 0, this would mean that we should play the alarm sound and show the “Time is up” dialog. Notice that although I am selecting the #alarm-ring audio element with jQuery, I am accessing the first DOM element within the collection so I get access to the JavaScript play() method that is available on audio elements.
TIme's up!
TIme’s up!
The last thing left to do, is to handle the “Set an alarm” dialog and the various buttons:
// Handle setting and clearing alamrs

$('.alarm-button').click(function(){

    // Show the dialog
    dialog.trigger('show');

});

dialog.find('.close').click(function(){
    dialog.trigger('hide')
});

dialog.click(function(e){

    // When the overlay is clicked, 
    // hide the dialog.

    if($(e.target).is('.overlay')){
        // This check is need to prevent
        // bubbled up events from hiding the dialog
        dialog.trigger('hide');
    }
});

alarm_set.click(function(){

    var valid = true, after = 0,
        to_seconds = [3600, 60, 1];

    dialog.find('input').each(function(i){

        // Using the validity property in HTML5-enabled browsers:

        if(this.validity && !this.validity.valid){

            // The input field contains something other than a digit,
            // or a number less than the min value

            valid = false;
            this.focus();

            return false;
        }

        after += to_seconds[i] * parseInt(parseInt(this.value));
    });

    if(!valid){
        alert('Please enter a valid number!');
        return;
    }

    if(after < 1){
        alert('Please choose a time in the future!');
        return; 
    }

    alarm_counter = after;
    dialog.trigger('hide');
});

alarm_clear.click(function(){
    alarm_counter = -1;

    dialog.trigger('hide');
});

// Custom events to keep the code clean
dialog.on('hide',function(){

    dialog.fadeOut();

}).on('show',function(){

    // Calculate how much time is left for the alarm to go off.

    var hours = 0, minutes = 0, seconds = 0, tmp = 0;

    if(alarm_counter > 0){

        // There is an alarm set, calculate the remaining time

        tmp = alarm_counter;

        hours = Math.floor(tmp/3600);
        tmp = tmp%3600;

        minutes = Math.floor(tmp/60);
        tmp = tmp%60;

        seconds = tmp;
    }

    // Update the input fields
    dialog.find('input').eq(0).val(hours).end().eq(1).val(minutes).end().eq(2).val(seconds);

    dialog.fadeIn();

});

time_is_up.click(function(){
    time_is_up.fadeOut();
});
There are a few interesting things about this code. Notice how I am using the built-in validity property on line 35, which is exists for the number input type in modern browsers. It tells us whether the content of the input field is a number greater than 0 (remember that they have a minimum value of 0).
Another other thing worth noting is the way the code for the alarm dialog is organized with custom events. When the show event is triggered, we calculate the remaining hours, minutes and seconds of the alarm, which are then inserted into the input fields.
With this our pretty digital clock with alarms is ready! I hope that you’ve liked this quick tutorial and will find it handy in your own projects .

0 comments:

Post a Comment