/**
* @typedef {Object} TimeRemaining
* @property {Number} days Days remaining
* @property {Number} hours Hours remaining
* @property {Number} minutes Minutes remaining
* @property {Number} seconds Seconds remaining
*/
/**
* Class representing a countdown.
*
* For full documentation, see the {@link https://wiki.tremorvideodsp.com/display/eng/Countdown Countdown Snippet Wiki Page}
*/
class Countdown {
/**
* Create a countdown.
* @param {Object} opts
* @param {Date} opts.date - Javascript Date Object.
* @param {Number} [opts.frequency=1] - Frequency of COUNTDOWN_TIME event.
* @param {String} [opts.suffix] - String to append to event names.
*/
constructor (opts) {
if (!opts || !opts.date) throw new Error('Countdown requires an options object with a date property')
if (!(opts.date instanceof Date)) throw new Error('The provided date must be an instance of the Date class')
this.date = opts.date
this.frequency = isNaN(opts.frequency) ? 1 : +opts.frequency
this.suffix = opts.suffix ? `_${opts.suffix}` : ''
this._inProgress = false
this._paused = false
this._interval = null
window.$b.on('AdPaused', () => {
this._paused = true
if (this._interval) this.stopCountdown()
})
window.$b.on('AdPlaying', () => {
this._paused = false
if (this._inProgress) this.startCountdown()
})
}
/**
* @summary Start the countdown.
* @param {Date} [newDate] A new Javascript Date Object to use for the countdown.
* @emits Countdown#COUNTDOWN_TIME - when called and at every tick
* @emits Countdown#COUNTDOWN_COMPLETE - when countdown is finished
*/
startCountdown (newDate) {
if (newDate) {
if (!(newDate instanceof Date)) throw new Error('The provided date must be an instance of the Date class')
if (this._interval) {
clearInterval(this._interval)
this._interval = null
}
this.date = newDate
}
if (this._paused || this._interval) return
let remainingTime = this.getRemainingTime()
if (remainingTime) {
/**
* @summary Event emitted on $b to pass up-to-date time info.
* @event Countdown#COUNTDOWN_TIME
* @type {TimeRemaining}
*/
window.$b.emit(`COUNTDOWN_TIME${this.suffix}`, remainingTime)
} else {
/**
* @summary Event emitted on $b to indicate the countdown is complete.
* @event Countdown#COUNTDOWN_COMPLETE
*/
window.$b.emit(`COUNTDOWN_COMPLETE${this.suffix}`)
return
}
this._interval = setInterval(() => {
let remainingTime = this.getRemainingTime()
if (remainingTime) {
window.$b.emit(`COUNTDOWN_TIME${this.suffix}`, remainingTime)
} else {
this.stopCountdown()
window.$b.emit(`COUNTDOWN_COMPLETE${this.suffix}`)
}
}, this.frequency * 1000)
this._inProgress = true
}
/**
* @summary Stop the countdown.
* @emits Countdown#COUNTDOWN_STOPPED - when called
*/
stopCountdown () {
if (!this._interval) return
clearInterval(this._interval)
this._interval = null
if (!this._paused) this._inProgress = false
/**
* @summary Event emitted on $b to indicate the countdown stopped.
* @event Countdown#COUNTDOWN_STOPPED
*/
window.$b.emit(`COUNTDOWN_STOPPED${this.suffix}`)
}
/**
* @summary Get the time remaining in the countdown.
* @return {TimeRemaining} Object with days, hours, minutes, and seconds properties.
*/
getRemainingTime () {
const ms = this.date - (new Date())
if (ms <= 0) return null
const totalS = Math.ceil(ms / 1000)
const seconds = totalS % 60
const totalM = Math.floor(totalS / 60)
const minutes = totalM % 60
const totalH = Math.floor(totalM / 60)
const hours = totalH % 24
const days = Math.floor(totalH / 24)
return { days, hours, minutes, seconds }
}
/**
* @summary Find out if countdown has completed.
* @return {Boolean} True if countdown has finished, otherwise False.
*/
hasCountdownFinished () {
return (new Date()) >= this.date
}
}
window.$b = window.$b || {}
window.$b.snippets = window.$b.snippets || {}
var snippets = window.$b.snippets
snippets.Countdown = Countdown
if (window.module) {
window.module.exports = Countdown
}