// == fs-flip-countdown Settings ==
var ctaElement = document.querySelector('.fs-flip-countdown-cta');
var dataEndsAt = ctaElement ? ctaElement.getAttribute('data-ends-at') : null;
var lang = 'DE'; // DE or EN description
var typeCountdown = 'date'; // 'time' to set the countdown to a specific time or 'date' to set the countdown to the designated date
var EndDate = dataEndsAt || '2026/02/01, 21:00'; // Expiration Date yyyy/mm/dd, hh:mm or ISO format. Working only if typeCountdown = 'date'
function parseEndDate(value) {
if (!value) { return new Date(); }
var parsed = new Date(value);
if (!isNaN(parsed.getTime())) { return parsed; }
var match = String(value).match(/^(\d{4})[\/\-](\d{2})[\/\-](\d{2})\s*,?\s*(\d{1,2}):(\d{2})$/);
if (match) {
var year = match[1];
var month = match[2];
var day = match[3];
var hour = match[4];
var minute = match[5];
return new Date(Number(year), Number(month) - 1, Number(day), Number(hour), Number(minute), 0);
}
return new Date();
}
var days = 1; // Number of days before the end. Working only if typeCountdown = 'time'
var timeOut = '00:00'; // 'hh:mm'. Number of hours and minutes before the end. Working only if typeCountdown = 'time'
var ColorDigitEnd = '#bfbfbf';
// == Settings END ==
var hours, minutes, target_date, ExpirationDate;
var formatCountdown = null;
var day_lang = '';
var hour_lang = '';
var minute_lang = '';
var second_lang = '';
function daysLeft(target) {
if (target > (24 * 60 * 60 * 1000)) { formatCountdown = 'day|hour|minute|second'; }
else if (target > (60 * 60 * 1000)) { formatCountdown = 'hour|minute|second'; }
else { formatCountdown = 'minute|second'; }
}
if (typeCountdown === 'time') {
timeOut = timeOut.split(':');
hours = timeOut[0];
minutes = timeOut[1];
target_date = ((days * 24 * 60 * 60 + hours * 60 * 60 + minutes * 60) * 1000);
daysLeft(target_date);
target_date += new Date().getTime();
} else if (typeCountdown === 'date') {
ExpirationDate = parseEndDate(EndDate);
target_date = (ExpirationDate - new Date());
daysLeft(target_date);
target_date += new Date().getTime();
}
else {
target_date = 0;
formatCountdown = 'day|hour|minute|second';
}
if (lang === 'DE') {
day_lang = 'Tage';
hour_lang = 'Stunden';
minute_lang = 'Minuten';
second_lang = 'Sekunden';
} else if (lang === 'EN') {
day_lang = 'Days';
hour_lang = 'Hours';
minute_lang = 'Minutes';
second_lang = 'Seconds';
}
function Countdown(userOptions) {
this.TIMESTAMP_SECOND = 1000;
this.TIMESTAMP_MINUTE = 60 * this.TIMESTAMP_SECOND;
this.TIMESTAMP_HOUR = 60 * this.TIMESTAMP_MINUTE;
this.TIMESTAMP_DAY = 24 * this.TIMESTAMP_HOUR;
this.options = {
cont: null,
countdown: true,
endDate: { day: 0, hour: 0, minute: 0, second: 0 },
endCallback: null,
outputFormat: formatCountdown,
outputTranslation: { day: day_lang, hour: hour_lang, minute: minute_lang, second: second_lang }
};
this.lastTick = null;
this.intervalsBySize = ['day', 'hour', 'minute', 'second'];
this.interval = null;
this.digitConts = {};
this._assignOptions(this.options, userOptions);
}
Countdown.prototype.start = function () {
var self = this;
this._fixCompatibility();
var endDate = this._getDate(this.options.endDate);
var endDateData = this._prepareTimeByOutputFormat(endDate);
this._writeData(endDateData);
this.lastTick = endDateData;
if (this.options.countdown && endDate.getTime() <= Date.now()) {
if (typeof this.options.endCallback === 'function') {
this.stop();
this.options.endCallback();
}
} else {
this.interval = setInterval(function () {
self._updateView(self._prepareTimeByOutputFormat(endDate));
}, this.TIMESTAMP_SECOND);
}
};
Countdown.prototype.stop = function () {
if (this.interval !== null) { clearInterval(this.interval); }
};
Countdown.prototype._getDate = function (date) {
if (typeof date === 'object') {
if (date instanceof Date) { return date; }
var expectedValues = { day: 0, hour: 0, minute: 0, second: 0 };
for (var i in expectedValues) {
if (expectedValues.hasOwnProperty(i) && date.hasOwnProperty(i)) { expectedValues[i] = date[i]; }
}
return new Date(expectedValues.day, expectedValues.hour, expectedValues.minute, expectedValues.second);
}
if (typeof date === 'number' || typeof date === 'string') { return new Date(date); }
return new Date();
};
Countdown.prototype._prepareTimeByOutputFormat = function (dateObj) {
var usedIntervals = [];
var output = {};
var timeDiff;
for (var i = 0; i < this.intervalsBySize.length; i++) {
var item = this.intervalsBySize[i];
if (this.options.outputFormat.split('|').indexOf(item) !== -1) { usedIntervals.push(item); }
}
timeDiff = this.options.countdown ? dateObj.getTime() - Date.now() : Date.now() - dateObj.getTime();
for (var j = 0; j < usedIntervals.length; j++) {
var interval = usedIntervals[j];
var value;
if (timeDiff > 0) {
switch (interval) {
case 'day':
value = Math.trunc(timeDiff / this.TIMESTAMP_DAY);
timeDiff -= value * this.TIMESTAMP_DAY;
break;
case 'hour':
value = Math.trunc(timeDiff / this.TIMESTAMP_HOUR);
timeDiff -= value * this.TIMESTAMP_HOUR;
break;
case 'minute':
value = Math.trunc(timeDiff / this.TIMESTAMP_MINUTE);
timeDiff -= value * this.TIMESTAMP_MINUTE;
break;
case 'second':
value = Math.trunc(timeDiff / this.TIMESTAMP_SECOND);
timeDiff -= value * this.TIMESTAMP_SECOND;
break;
}
} else {
value = '00';
var elements = document.querySelectorAll('.fs-flip-digit-cont');
for (var k = 0; k < elements.length; k++) { elements[k].style.color = ColorDigitEnd; }
}
output[interval] = ((('' + value).length < 2 ? '0' + value : '' + value)).split('');
}
return output;
};
Countdown.prototype._fixCompatibility = function () {
Math.trunc = Math.trunc || function (x) {
if (isNaN(x)) { return NaN; }
if (x > 0) { return Math.floor(x); }
return Math.ceil(x);
};
};
Countdown.prototype._writeData = function (data) {
var code = '';
for (var intervalName in data) {
if (data.hasOwnProperty(intervalName)) {
var element = '
';
var intervalDescription = '
' + this.options.outputTranslation[intervalName] + '
';
for (var index = 0; index < data[intervalName].length; index++) {
var digit = data[intervalName][index];
element += '
' + this._getDigitElementString(digit, 0) + '
';
}
code += element + '
' + intervalDescription + '
';
}
}
this.options.cont.innerHTML = code;
this.lastTick = data;
};
Countdown.prototype._getDigitElementString = function (newDigit, lastDigit) {
return ''
+ '
' + lastDigit + '
'
+ '
' + newDigit + '
'
+ '
' + lastDigit + '
'
+ '
'
+ '
' + newDigit + '
'
+ '
';
};
Countdown.prototype._updateView = function (data) {
for (var intervalName in data) {
if (data.hasOwnProperty(intervalName)) {
for (var index = 0; index < data[intervalName].length; index++) {
var digit = data[intervalName][index];
if (this.lastTick !== null && this.lastTick[intervalName][index] !== digit) {
this._getDigitCont(intervalName, index).innerHTML = this._getDigitElementString(digit, this.lastTick[intervalName][index]);
}
}
}
}
this.lastTick = data;
};
Countdown.prototype._getDigitCont = function (intervalName, index) {
var key = intervalName + '_' + index;
if (!this.digitConts[key]) {
this.digitConts[key] = this.options.cont.querySelector('.fs-flip-interval-cont_' + intervalName + ' .fs-flip-digit-cont_' + index);
}
return this.digitConts[key];
};
Countdown.prototype._assignOptions = function (options, userOptions) {
for (var i in options) {
if (options.hasOwnProperty(i) && userOptions.hasOwnProperty(i)) {
if (options[i] !== null && typeof options[i] === 'object' && typeof userOptions[i] === 'object') {
this._assignOptions(options[i], userOptions[i]);
} else {
options[i] = userOptions[i];
}
}
}
};
var cd = new Countdown({
cont: document.querySelector('.fs-flip-countdown'),
endDate: target_date,
outputTranslation: {
day: day_lang,
hour: hour_lang,
minute: minute_lang,
second: second_lang
},
endCallback: null,
outputFormat: formatCountdown
});
cd.start();