Skip to content

Added support for > 99 days, bower, UMD #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions bower.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "jQuery-Countdown",
"homepage": "https://github.com/martinaglv/jQuery-Countdown",
"authors": [
"Martin Angelov"
],
"description": "A simple jQuery plugin for creating a countdown timer.",
"main": "./countdown/jquery.countdown.js",
"moduleType": [
"amd",
"globals",
"node"
],
"keywords": [
"countdown"
],
"license": "MIT",
"private": true,
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"jquery": "~1.11.3 || ~2.1.4"
}
}
259 changes: 169 additions & 90 deletions countdown/jquery.countdown.js
Original file line number Diff line number Diff line change
@@ -1,138 +1,217 @@
/**
* @name jQuery Countdown Plugin
* @author Martin Angelov
* @version 1.0
* @version 1.1
* @url http://tutorialzine.com/2011/12/countdown-jquery/
* @link https://github.com/martinaglv/jQuery-Countdown
* @license MIT License
*
* Changelog:
* ----------
*
* v1.0 Initial Commit
* v1.1 Add support for more than 99 days
*/

(function($){

(function (root, factory) {
if (typeof define === "function" && define.amd) {
// AMD
define(["jquery"], factory);
} else if (typeof exports === "object") {
// Node, CommonJS-like
module.exports = factory(require("jquery"));
} else {
// Browser globals (root is window)
root.jcountdown = factory(root.$);
}
}(this, function ($) {
'use strict';

// Number of seconds in every time division
var days = 24*60*60,
hours = 60*60,
minutes = 60;

// Creating the plugin

/**
* Creating the plugin
*
* @param prop
* @returns {jQuery}
*/
$.fn.countdown = function(prop){

var options = $.extend({
callback : function(){},
timestamp : 0
},prop);

var left, d, h, m, s, positions;
}, prop);

// Initialize the plugin
init(this, options);

positions = this.find('.position');


// Get the position elements once the html has been set in the init above
var positions = this.find('.position');

(function tick(){

// Time left
left = Math.floor((options.timestamp - (new Date())) / 1000);

if(left < 0){
left = 0;
}

// Number of days left
d = Math.floor(left / days);
updateDuo(0, 1, d);
left -= d*days;

// Number of hours left
h = Math.floor(left / hours);
updateDuo(2, 3, h);
left -= h*hours;

// Number of minutes left
m = Math.floor(left / minutes);
updateDuo(4, 5, m);
left -= m*minutes;

// Number of seconds left
s = left;
updateDuo(6, 7, s);

var time = calculateRemainingTime(options.timestamp),
position = 0;

$.each(time, function(index, value) {
var digits = getDigits(value);

// We might have to shift 1 places (because we normalized to a minimum of 2 digits)
if(digits < 2) {
value = '0' + value;
digits = 2;
}

for(var i = 0; i < digits; i++){
switchDigit(positions.eq(position), value.toString()[i]);
position++;
}
});

// Calling an optional user supplied callback
options.callback(d, h, m, s);
options.callback(time.d, time.h, time.m, time.s);

// Scheduling another call of this function in 1s
setTimeout(tick, 1000);
})();

// This function updates two digit positions at once
function updateDuo(minor,major,value){
switchDigit(positions.eq(minor),Math.floor(value/10)%10);
switchDigit(positions.eq(major),value%10);
}


return this;
};

/**
* Calculate the amount of time ramaining given a timestamp
*
* @param {number} timestamp - A timestamp in seconds (Unix date)
* @returns {Object} The remaining time to the present
*/
function calculateRemainingTime (timestamp) {
var left, time = {};

// Time left
left = (timestamp - new Date().getTime()) / 1000;
left = left < 0 && 0 || left;

// Number of days left
time.d = Math.floor(left / days);
left -= time.d * days;

// Number of hours left
time.h = Math.floor(left / hours);
left -= time.h * hours;

// Number of minutes left
time.m = Math.floor(left / minutes);
left -= time.m * minutes;

// Number of seconds left
time.s = Math.floor(left);

return time;
}

/**
* Get the number of digits of a number
*
* @param {number} number
* @returns {number} - The number of digits
*/
function getDigits(number) {
return number ? Math.log(number) * Math.LOG10E + 1 | 0 : 1;
}

/**
* Returns an HTML string containing a certain number of digits
*
* @param {number} number
* @returns {String} - An HTML string
*/
function getDigitsHTML(number) {
var digitHTML = '<span class="position"><span class="digit static">0</span></span>',
digitsHTML = '',
digits = getDigits(number);

// Normalize minimum number of digits (we always show at least 2 digits)
if(digits < 2) digits = 2;

// Build the digits html
for(var i = 0; i < digits; i++){
digitsHTML += digitHTML;
}

return digitsHTML;
}

/**
* Initializes the countdown widget
*
* @param {jQuery} elem - The wrapper element for the countdown
* @param {Object} options - Contains the callback and timestamp arguments
* @returns {void}
*/
function init(elem, options){
// Get the time offset from the start
var time = calculateRemainingTime(options.timestamp);

// Add own class to countdown wrapper
elem.addClass('countdownHolder');

// Creating the markup inside the container
$.each(['Days','Hours','Minutes','Seconds'],function(i){
$('<span class="count'+this+'">').html(
'<span class="position">\
<span class="digit static">0</span>\
</span>\
<span class="position">\
<span class="digit static">0</span>\
</span>'
$.each(['d','h','m','s'], function(index, value){
$('<span class="count'+ this +'">').html(
getDigitsHTML(time[value])
).appendTo(elem);
if(this!="Seconds"){
elem.append('<span class="countDiv countDiv'+i+'"></span>');

if(this !== "s"){
elem.append('<span class="countDiv countDiv'+ index +'"></span>');
}
});

}

// Creates an animated transition between the two numbers
function switchDigit(position,number){

var digit = position.find('.digit')

if(digit.is(':animated')){
/**
* Creates an animated transition between the two numbers
*
* Note: The .static class is added when the animation completes. This makes it run smoother.
*
* @param position
* @param {number} number
* @returns {boolean} - TRUE if it switched the digit
*/
function switchDigit(position, number){
var digit = position.find('.digit'),
replacement = $('<span>',{
'class':'digit',
css: {
top:'-2.1em',
opacity:0
},
html: number
});

// No transition is necessary
if(digit.is(':animated'))
return false;
}

if(position.data('digit') == number){
// We are already showing this number

// We are already showing this number
if(position.data('digit') == number)
return false;
}

position.data('digit', number);

var replacement = $('<span>',{
'class':'digit',
css:{
top:'-2.1em',
opacity:0
},
html:number
});

// The .static class is added when the animation
// completes. This makes it run smoother.


position
.data('digit', number);

digit
.before(replacement)
.removeClass('static')
.animate({top:'2.5em',opacity:0},'fast',function(){
.animate({top:'2.5em', opacity:0}, 'fast', function(){
digit.remove();
})
});

replacement
.delay(100)
.animate({top:0,opacity:1},'fast',function(){
.animate({top:0, opacity:1}, 'fast', function(){
replacement.addClass('static');
});

return true;
}
})(jQuery);
}));