Skip to content

Instantly share code, notes, and snippets.

@benben77
Created May 11, 2015 09:52
Show Gist options
  • Save benben77/adfbf2ac83f2f9d66387 to your computer and use it in GitHub Desktop.
Save benben77/adfbf2ac83f2f9d66387 to your computer and use it in GitHub Desktop.
JS util for generate countdown string
(function(define) {
var SECONDS = {
second: 1,
minute: 60
};
SECONDS.hour = SECONDS.minute * 60;
SECONDS.day = SECONDS.hour * 24;
SECONDS.week = SECONDS.day * 7;
var TIME_ARR = ['year', 'month', 'week', 'day', 'hour', 'minute', 'second'],
TIME_ARR2 = TIME_ARR.slice(2);
function twoNumber(number) {
if (number < 10) {
return '0' + number;
} else {
return '' + number;
}
}
var numberFunctions = {
'%Y': {
name: 'year',
twoNumber: false
},
'%YY': {
name: 'year',
twoNumber: true
},
'%M': {
name: 'month',
twoNumber: false
},
'%MM': {
name: 'month',
twoNumber: true
},
'%w': {
name: 'week',
twoNumber: false
},
'%ww': {
name: 'week',
twoNumber: true
},
'%d': {
name: 'day',
twoNumber: false
},
'%dd': {
name: 'day',
twoNumber: true
},
'%h': {
name: 'hour',
twoNumber: false
},
'%hh': {
name: 'hour',
twoNumber: true
},
'%m': {
name: 'minute',
twoNumber: false
},
'%mm': {
name: 'minute',
twoNumber: true
},
'%s': {
name: 'second',
twoNumber: false
},
'%ss': {
name: 'second',
twoNumber: true
}
};
var matchNumberFunctions1 = /(%YY|%MM|%ww|%dd|%hh|%mm|%ss)/,
matchNumberFunctions2 = /(%Y|%M|%w|%d|%h|%m|%s)/;
function setTop(config, top) {
TIME_ARR.forEach(function(key, i) {
if (config[key]) {
for (var j = i + 1; j < TIME_ARR.length; j++) {
top[TIME_ARR[j]] = key;
}
}
});
}
function compileCountDown(format) {
var arr = format.split(/(\(.+?\))/g).filter(function(str) {
return str
}),
config = {},
top = {},
funcArr = arr.map(function(str) {
var matched1 = str.match(matchNumberFunctions1),
matched2 = str.match(matchNumberFunctions2);
if (matched1 || matched2) {
var key = (matched1 && matched1[0]) || matched2[0],
temp = numberFunctions[key];
config[temp.name] = true;
str = str.replace(/(^\(|\)$)/g, '');
return function(timeObj) {
var timeNumber = timeObj[temp.name];
if (timeNumber === -1) {
return '';
} else {
var result = temp.twoNumber ? twoNumber(timeNumber) : timeNumber;
return str.replace(key, result).replace(/({.+?})/, function(pluralStr) {
var pruralArr = pluralStr.replace(/(^{|}$)/g, '').split('|');
if (pruralArr.length === 1 || timeNumber === 0 || timeNumber === 1) {
return pruralArr[0];
} else {
return pruralArr[1];
}
});
}
};
} else {
return str;
}
});
setTop(config, top);
return function(target, now) {
return execCountDown(funcArr, target, now, config, top);
};
}
function execCountDown(funcArr, target, now, config, top) {
var timeObj = getTimeObj(target, now, config, top);
return funcArr.map(function(item) {
if (typeof item === 'function') {
return item(timeObj);
} else {
return item;
}
}).join('');
}
function getTimeObj(target, now, config, top) {
var timeObj = {},
seconds;
if (config.year) {
var diff = target.getYear() - now.getYear();
if (diff > 0) {
var now2 = new Date(now.getTime());
now2.setFullYear(now2.getFullYear() + diff);
if (now2.getTime() > target.getTime()) {
now2.setFullYear(now2.getFullYear() - 1);
timeObj.year = diff - 1;
} else {
timeObj.year = diff;
}
now = now2;
} else {
timeObj.year = 0;
}
}
if (config.month) {
var diff = (target.getMonth() + target.getYear() * 12) - (now.getMonth() + now.getYear() * 12);
if (diff > 0) {
var now2 = new Date(now.getTime());
now2.setMonth(now2.getMonth() + diff);
if (now2.getTime() > target.getTime()) {
now2.setMonth(now2.getMonth() - 1);
timeObj.month = diff - 1;
} else {
timeObj.month = diff;
}
now = now2;
} else {
timeObj.month = 0;
}
}
seconds = ((target.getTime() - now.getTime()) / 1000);
TIME_ARR2.forEach(function(key, i) {
if (config[key]) {
var number = seconds;
if (top[key] && SECONDS[top[key]]) {
number = number % SECONDS[top[key]];
}
timeObj[key] = parseInt(number / SECONDS[key], 10)
}
});
TIME_ARR.forEach(function(key, i) {
if (key in timeObj && timeObj[key] === 0) {
var flag = true;
for (var j = i - 1; j >= 0; j--) {
var temp = timeObj[TIME_ARR[j]];
if (temp && temp !== -1) {
flag = false;
break;
}
}
if (flag) {
timeObj[key] = -1;
}
}
});
return timeObj;
};
if (define) {
define(function(require) {
return compileCountDown;
});
} else {
window.CountDown = compileCountDown;
}
return compileCountDown;
})(window.define);
// todo: performance & code clear up ; until & since
example usage:
var SECONDS = {
second: 1,
minute: 60
};
SECONDS.hour = SECONDS.minute * 60;
SECONDS.day = SECONDS.hour * 24;
SECONDS.week = SECONDS.day * 7;
(function () {
var format = 'still (%w {week|weeks}, )(%dd {d}, )(%hh:)(%mm:)(%ss) to event',
seconds = SECONDS.week * 2 + SECONDS.day * 5 + SECONDS.hour * 17 + SECONDS.minute * 45 + 15,
div = document.getElementById('div1'),
func = CountDown(format),
target = new Date(new Date().getTime() + seconds*1000);
setInterval(function () {
div.innerHTML = func(target, new Date());
}, 1000);
})();
(function () {
var format = 'still (%h {hour|hours} )(%m {min|mins}) to event',
seconds = SECONDS.day * 2 + SECONDS.hour * 5 + SECONDS.minute * 11 + 15,
div = document.getElementById('div2'),
func = CountDown(format),
target = new Date(new Date().getTime() + seconds*1000);
setInterval(function () {
div.innerHTML = func(target, new Date());
}, 1000);
})();
(function () {
var format = 'still (%w {week|weeks}, )(%dd {d}, )(%hh:)(%mm:)(%ss) to event',
seconds = SECONDS.week * 0 + SECONDS.day * 1 + SECONDS.hour * 0 + SECONDS.minute * 0 + 15,
div = document.getElementById('div3'),
func = CountDown(format),
target = new Date(new Date().getTime() + seconds*1000);
setInterval(function () {
div.innerHTML = func(target, new Date());
}, 1000);
})();
(function () {
var format = 'still (%M {month|months}, )(%dd {d}, )(%hh:)(%mm:)(%ss) to event',
seconds = SECONDS.week * 5 + SECONDS.day * 1 + SECONDS.hour * 0 + SECONDS.minute * 0 + 15,
div = document.getElementById('div4'),
func = CountDown(format),
target = new Date(new Date().getTime() + seconds*1000);
setInterval(function () {
div.innerHTML = func(target, new Date());
}, 1000);
})();
(function () {
var format = 'still (%Y {year|years}, )(%M {month|months}, )(%w {week|weeks}, )(%d {day|days}, )(%hh:)(%mm:)(%ss) to event',
seconds = SECONDS.week * 72 + SECONDS.day * 1 + SECONDS.hour * 0 + SECONDS.minute * 0 + 15,
div = document.getElementById('div5'),
func = CountDown(format),
target = new Date(new Date().getTime() + seconds*1000);
setInterval(function () {
div.innerHTML = func(target, new Date());
}, 1000);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment