@toreda/time
Version:
Simple, small footprint library for common time operations and converting between units of time.
206 lines (205 loc) • 7.35 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TimerActive = void 0;
const strong_types_1 = require("@toreda/strong-types");
const defaults_1 = require("../defaults");
const group_1 = require("./callback/group");
const make_1 = require("../time/make");
const now_1 = require("../time/now");
/**
* Active timer with internal timing clock. Takes a callback to invoke
* every timer trigger.
*
* @category Timers
*/
class TimerActive {
constructor(options) {
this.lastIntervalEnd = (0, strong_types_1.floatMake)(0);
this.running = (0, strong_types_1.boolMake)(false);
this._handlersBound = (0, strong_types_1.boolMake)(false);
const limitDuration = typeof (options === null || options === void 0 ? void 0 : options.limitDuration) === 'boolean' ? options === null || options === void 0 ? void 0 : options.limitDuration : false;
this.limitDuration = (0, strong_types_1.boolMake)(limitDuration);
this._checkIntervalMs = (0, make_1.timeMake)('ms', defaults_1.Defaults.Timer.CheckIntervalMs);
this.timeStart = (0, make_1.timeMake)('s', 0);
this.timeStop = (0, make_1.timeMake)('s', 0);
const timeLimit = typeof (options === null || options === void 0 ? void 0 : options.timeLimit) === 'number' ? options === null || options === void 0 ? void 0 : options.timeLimit : 0;
this.timeLimit = (0, make_1.timeMake)('s', timeLimit);
this.paused = (0, strong_types_1.boolMake)(false);
this.listeners = {
start: new group_1.TimerCallbackGroup('start'),
stop: new group_1.TimerCallbackGroup('stop'),
pause: new group_1.TimerCallbackGroup('pause'),
unpause: new group_1.TimerCallbackGroup('unpause'),
done: new group_1.TimerCallbackGroup('done'),
restart: new group_1.TimerCallbackGroup('restart'),
reset: new group_1.TimerCallbackGroup('reset')
};
}
getListenerGroup(id) {
if (typeof id !== 'string') {
return null;
}
const group = this.listeners[id];
if (!group) {
return null;
}
return group;
}
on(id, fn) {
if (typeof fn !== 'function') {
return false;
}
const group = this.getListenerGroup(id);
if (!group) {
return false;
}
group._always().push(fn);
return true;
}
once(id, fn) {
if (typeof fn !== 'function') {
return false;
}
const group = this.getListenerGroup(id);
if (!group) {
return false;
}
group._once().push(fn);
return true;
}
setTimeLimit(value) {
if (value === undefined || value === null) {
return false;
}
if (typeof value === 'number') {
this.timeLimit.set(value);
return true;
}
if (value.type === 'Time') {
this.timeLimit.set(value.asSeconds());
return true;
}
return false;
}
bindHandlers() {
if (this._handlersBound()) {
return;
}
// Mark handlers as bound.
this._handlersBound(true);
this.start = this.start.bind(this);
this.stop = this.stop.bind(this);
this.reset = this.reset.bind(this);
this.onUpdate = this.onUpdate.bind(this);
}
unpause() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.running() || !this.paused()) {
return false;
}
yield this.executeCallbacks('unpause');
this.paused(false);
return true;
});
}
pause() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.running() || this.paused()) {
return false;
}
yield this.executeCallbacks('pause');
return this.paused(true);
});
}
/**
* Start the timer.
* @returns
*/
start() {
return __awaiter(this, void 0, void 0, function* () {
// Timer is already running.
if (this.running()) {
return false;
}
this.bindHandlers();
this.timeStart.setNow();
this._timerHandle = setTimeout(this.onUpdate, defaults_1.Defaults.Timer.CheckIntervalMs);
yield this.executeCallbacks('start');
return this.running(true);
});
}
done() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.running()) {
return false;
}
yield this.executeCallbacks('done');
return this.stop();
});
}
stop() {
return __awaiter(this, void 0, void 0, function* () {
// Time isn't running. Nothing to stop!
if (!this.running()) {
return false;
}
clearInterval(this._timerHandle);
this.timeStop.setNow();
const timeSince = this.timeStart.since(this.timeStop());
const value = timeSince ? timeSince() : 0;
this.listeners.stop.always(value);
this.running(false);
return true;
});
}
executeCallbacks(eventId) {
return __awaiter(this, void 0, void 0, function* () {
const group = this.listeners[eventId];
if (!group) {
return;
}
const now = (0, now_1.timeNow)();
const timeSince = now.since(now());
const duration = timeSince ? timeSince() : 0;
yield group.execute(duration);
});
}
reset() {
this.stop();
this.lastIntervalEnd.reset();
this.listeners.done.reset();
this.listeners.pause.reset();
this.listeners.reset.reset();
this.listeners.restart.reset();
this.listeners.start.reset();
this.listeners.stop.reset();
this.listeners.unpause.reset();
this.running(false);
this.paused(false);
this.limitDuration.reset();
}
onUpdate() {
if (!this.running()) {
return;
}
const now = (0, now_1.timeNow)();
// Fixed duration timers should stop when reaching their time limit.
if (this.limitDuration()) {
const duration = this.timeStart.since(now);
if (duration && duration() >= this.timeLimit()) {
this.done();
return;
}
}
}
}
exports.TimerActive = TimerActive;