UNPKG

@ribajs/moment

Version:

Moment.js module for Riba.js

218 lines (182 loc) 5.69 kB
import { Component, TemplateFunction, ScopeBase } from "@ribajs/core"; interface Scope extends ScopeBase { time: string; countdownYears: boolean; countdownDays: boolean; countdownHours: boolean; countdownMinutes: boolean; countdownSeconds: boolean; countdownRunning: boolean; remainingYears: number; remainingDays: number; remainingHours: number; remainingMinutes: number; remainingSeconds: number; } ///TODO: Add "timer" mode, which starts at a given point in time, // and counts the time passed since than, and a mixed // mode, which is basically a countdown and after the countdown reached 0, // it continues as a "timer". export class TimerComponent extends Component { public static tagName = "moment-timer"; protected autobind = true; static get observedAttributes(): string[] { return [ "time", "countdown-years", "countdown-days", "countdown-hours", "countdown-minutes", "countdown-seconds", ]; } protected requiredAttributes(): string[] { return ["time"]; } public scope: Scope = { countdownYears: false, countdownDays: true, countdownHours: true, countdownMinutes: true, countdownSeconds: true, countdownRunning: true, remainingYears: 0, remainingDays: 0, remainingHours: 0, remainingMinutes: 0, remainingSeconds: 0, time: "", }; private updateIntervalId?: number; constructor() { super(); } protected connectedCallback() { super.connectedCallback(); this.init(TimerComponent.observedAttributes); this.startCountdownInterval(); } protected async init(observedAttributes: string[]) { return super.init(observedAttributes); } protected async beforeBind() { return await super.beforeBind(); } protected async afterBind() { await super.afterBind(); } protected updateCountdown() { //calculate seconds until countdown is over let remainingSeconds = this.getRemainingSeconds(); if (!remainingSeconds || remainingSeconds < 1) { this.cancelCountdownInterval(); this.resetCountdown(); return; } this.scope.countdownRunning = true; const secsOfMinute = 60; const secsOfHour = 60 * secsOfMinute; const secsOfDay = 24 * secsOfHour; const secsOfYear = 365 * secsOfDay; // TODO leap year (Schaltjahr) if (this.scope.countdownYears) { if (this.isYearsLastUnit()) { this.scope.remainingYears = Math.ceil(remainingSeconds / secsOfYear); return; } else { this.scope.remainingYears = Math.floor(remainingSeconds / secsOfYear); remainingSeconds -= this.scope.remainingYears * secsOfYear; } } if (this.scope.countdownDays) { if (this.isDaysLastUnit()) { this.scope.remainingDays = Math.ceil(remainingSeconds / secsOfDay); return; } else { this.scope.remainingDays = Math.floor(remainingSeconds / secsOfDay); remainingSeconds -= this.scope.remainingDays * secsOfDay; } } if (this.scope.countdownHours) { if (this.isHoursLastUnit()) { this.scope.remainingHours = Math.ceil(remainingSeconds / secsOfHour); return; } else { this.scope.remainingHours = Math.floor(remainingSeconds / secsOfHour); remainingSeconds -= this.scope.remainingHours * secsOfHour; } } if (this.scope.countdownMinutes) { if (this.isMinutesLastUnit()) { this.scope.remainingMinutes = Math.ceil( remainingSeconds / secsOfMinute, ); return; } else { this.scope.remainingMinutes = Math.floor( remainingSeconds / secsOfMinute, ); remainingSeconds -= this.scope.remainingMinutes * secsOfMinute; } } this.scope.remainingSeconds = Math.ceil(remainingSeconds); } protected resetCountdown() { this.scope.remainingDays = 0; this.scope.remainingHours = 0; this.scope.remainingMinutes = 0; this.scope.remainingSeconds = 0; } //returns remaining seconds until this.scope.time is reached. protected getRemainingSeconds(): number { return Math.ceil( (Date.parse(this.scope.time) - new Date().getTime()) / 1000, ); } protected isYearsLastUnit(): boolean { return ( this.scope.countdownYears == false && this.scope.countdownHours == false && this.scope.countdownMinutes == false && this.scope.countdownSeconds == false ); } protected isDaysLastUnit(): boolean { return ( this.scope.countdownHours == false && this.scope.countdownMinutes == false && this.scope.countdownSeconds == false ); } protected isHoursLastUnit(): boolean { return ( this.scope.countdownMinutes == false && this.scope.countdownSeconds == false ); } protected isMinutesLastUnit(): boolean { return this.scope.countdownSeconds == false; } protected startCountdownInterval() { this.scope.countdownRunning = false; //call function immediatly to remove initial delay this.updateCountdown(); //create interval and save id to clear later to prevent resource leaking this.updateIntervalId = window.setInterval(() => { this.updateCountdown(); }, 1000); } protected cancelCountdownInterval() { this.scope.countdownRunning = false; if (this.updateIntervalId) window.clearInterval(this.updateIntervalId); this.updateIntervalId = undefined; } // deconstruction protected disconnectedCallback() { super.disconnectedCallback(); this.cancelCountdownInterval(); } protected template(): ReturnType<TemplateFunction> { return null; } }