@stimulus-library/controllers
Version:
A library of useful controllers for Stimulus
154 lines (153 loc) • 4.91 kB
JavaScript
import { intervalToDuration } from "date-fns/intervalToDuration";
import { isPast } from "date-fns/isPast";
import { BaseController } from "@stimulus-library/utilities";
import { installClassMethods } from "@stimulus-library/mixins";
export class CountdownController extends BaseController {
constructor() {
super(...arguments);
this._timeout = null;
}
get _removeUnused() {
return this.hasRemoveUnusedValue ? this.removeUnusedValue : false;
}
get _padZeros() {
return this.hasPadZerosValue ? this.padZerosValue : true;
}
get _deadlineDate() {
return new Date(this.deadlineValue);
}
initialize() {
this._tick = this._tick.bind(this);
}
connect() {
this._timeout = setTimeout(this._tick, 1000);
installClassMethods(this);
this.addCountingDownClasses();
}
disconnect() {
this._clearTick();
this.removeCountingDownClasses();
this.removeEndedClasses();
}
deadlineValueChanged() {
if (this._timeout == null) {
this._timeout = setTimeout(this._tick, 1000);
}
}
_tick() {
try {
const now = new Date();
let distance = {};
if (isPast(this._deadlineDate)) {
distance = { years: 0, months: 0, days: 0, hours: 0, minutes: 0, seconds: 0 };
this._clearTick();
this.removeCountingDownClasses();
this.addEndedClasses();
this.dispatchEvent(this.el, this.eventName("ended"));
return;
}
else {
distance = intervalToDuration({ start: now, end: this._deadlineDate });
this._timeout = setTimeout(this._tick, 1000);
}
if (this.hasYearsTarget) {
this._updateTarget(this.yearsTarget, this._years(distance));
}
if (this.hasMonthsTarget) {
this._updateTarget(this.monthsTarget, this._months(distance));
}
if (this.hasDaysTarget) {
this._updateTarget(this.daysTarget, this._days(distance));
}
if (this.hasHoursTarget) {
this._updateTarget(this.hoursTarget, this._hours(distance));
}
if (this.hasMinutesTarget) {
this._updateTarget(this.minutesTarget, this._minutes(distance));
}
if (this.hasSecondsTarget) {
this._updateTarget(this.secondsTarget, this._seconds(distance));
}
}
catch (e) {
console.error(e);
this._clearTick();
}
}
_clearTick() {
if (this._timeout) {
clearTimeout(this._timeout);
this._timeout = null;
}
}
_updateTarget(target, value) {
this._removeTargetIfUnused(target, value);
target.innerHTML = value;
}
_removeTargetIfUnused(target, value) {
let intValue = Number.parseInt(value);
if (this._removeUnused) {
if (intValue === 0 && target.dataset.unused) {
let number = Number.parseInt(target.dataset.unused);
if (number < Date.now() - 1000) {
target.remove();
}
}
else if (intValue == 0) {
target.dataset.unused = Date.now().toString();
}
else {
delete target.dataset.unused;
}
}
}
_years(duration) {
let unit = duration.years || 0;
return (unit > 0 ? unit : 0).toString();
}
_months(duration) {
let unit = duration.months || 0;
return (unit > 0 ? unit : 0).toString();
}
_days(duration) {
let unit = duration.days || 0;
return (unit > 0 ? unit : 0).toString();
}
_hours(duration) {
let unit = duration.hours || 0;
let str = (unit > 0 ? unit : 0).toString();
if (this._padZeros) {
return str.padStart(2, "0");
}
else {
return str;
}
}
_minutes(duration) {
let unit = duration.minutes || 0;
let str = (unit > 0 ? unit : 0).toString();
if (this._padZeros) {
return str.padStart(2, "0");
}
else {
return str;
}
}
_seconds(duration) {
let unit = duration.seconds || 0;
let str = (unit > 0 ? unit : 0).toString();
if (this._padZeros) {
return str.padStart(2, "0");
}
else {
return str;
}
}
}
CountdownController.values = {
deadline: String,
removeUnused: Boolean,
padZeros: Boolean,
};
CountdownController.targets = ["years", "months", "days", "hours", "minutes", "seconds"];
CountdownController.classes = ["countingDown", "ended"];