@oscarpalmer/timer 0.6.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -2
- package/dist/timer.cjs +2 -0
- package/dist/timer.cjs.map +7 -0
- package/dist/timer.iife.js +2 -0
- package/dist/timer.iife.js.map +7 -0
- package/dist/timer.js +41 -51
- package/dist/timer.js.map +7 -0
- package/package.json +28 -19
- package/src/index.ts +51 -55
- package/.eslintrc.json +0 -44
- package/test/index.html +0 -24
- package/test/test.js +0 -121
- package/tsconfig.json +0 -31
package/README.md
CHANGED
|
@@ -1,7 +1,65 @@
|
|
|
1
1
|
# Timer
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://badge.fury.io/js/@oscarpalmer%2Ftimer)
|
|
4
|
+
|
|
5
|
+
A better solution for timeout- and interval-based timers.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Timer is available on _npm_ as [`@oscarpalmer/timer`](https://www.npmjs.com/package/@oscarpalmer/timer) to be bundled with your awesome projects.
|
|
10
|
+
|
|
11
|
+
If you don't need to bundle things, you can use the CDN-version and include a script in your proejcts right away, thanks to [jsDelivr](https://www.jsdelivr.com/package/npm/@oscarpalmer/timer) and [UNPKG](https://unpkg.com/@oscarpalmer/timer).
|
|
12
|
+
|
|
13
|
+
## Getting started
|
|
14
|
+
|
|
15
|
+
This is fairly lightweight package, so hopefully you'll be up and running in seconds :blush:
|
|
16
|
+
|
|
17
|
+
### Examples
|
|
18
|
+
|
|
19
|
+
The timers can be called with nice helper methods, which also auto-starts the timers:
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import {repeat, wait} from '@oscarpalmer/timer';
|
|
23
|
+
|
|
24
|
+
let waited = wait(callback, time);
|
|
25
|
+
let repeated = repeat(callback, time, count);
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or they can be created using class syntax, but without being auto-started:
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import {Repeated, Waited} from '@oscarpalmer/timer';
|
|
32
|
+
|
|
33
|
+
waited = new Waited(callback, time);
|
|
34
|
+
repeated = new Repeated(callback, time, count);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### CDN & IIFE
|
|
38
|
+
|
|
39
|
+
If you're using Timer by including the file suffixed with `.iife.js` – or one of the CDN-versions mentioned above – you won't have to import any of the classes or methods.
|
|
40
|
+
|
|
41
|
+
Instead, just include a `script`-tag in your HTML linking to Timer and you can access Timer in other scripts, as below:
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// With auto-start
|
|
45
|
+
var waited = Timer.wait(callback, time);
|
|
46
|
+
var repeated = Timer.repeat(callback, time, count);
|
|
47
|
+
|
|
48
|
+
// With manual start
|
|
49
|
+
waited = new Timer.Waited(callback, time);
|
|
50
|
+
repeated = new Timer.Repeated(callback, time, count);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Methods
|
|
54
|
+
|
|
55
|
+
Both the nice helper methods and the class syntax create similar objects – `Waited` and `Repeated` – which share methods:
|
|
56
|
+
|
|
57
|
+
|Method|Description|
|
|
58
|
+
|-----:|:----------|
|
|
59
|
+
|`start()`|Starts the timer: necessary when creating a timer using the class syntax _(e.g. `new Waited...`)_, but helpful when the timer needs to be started at other times, as well|
|
|
60
|
+
|`stop()`|Stops the timer|
|
|
61
|
+
|`restart()`|Restarts the timer|
|
|
4
62
|
|
|
5
63
|
## License
|
|
6
64
|
|
|
7
|
-
[MIT licensed](LICENSE), natch :
|
|
65
|
+
[MIT licensed](LICENSE), natch :wink:
|
package/dist/timer.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var c=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var w=(t,e,n)=>e in t?c(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var k=(t,e)=>{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},g=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of m(e))!v.call(t,a)&&a!==n&&c(t,a,{get:()=>e[a],enumerable:!(r=h(e,a))||r.enumerable});return t};var y=t=>g(c({},"__esModule",{value:!0}),t);var u=(t,e,n)=>(w(t,typeof e!="symbol"?e+"":e,n),n);var A={};k(A,{Repeated:()=>i,Waited:()=>l,repeat:()=>C,wait:()=>x});module.exports=y(A);var p=Math.round(16.666666666666668),s=class{constructor(e,n,r){u(this,"callback");u(this,"count");u(this,"frame");u(this,"running",!1);u(this,"time");let a=this instanceof i,o=a?"repeated":"waited";if(typeof e!="function")throw new Error(`A ${o} timer must have a callback function`);if(typeof n!="number"||n<0)throw new Error(`A ${o} timer must have a non-negative number as its time`);if(a&&(typeof r!="number"||r<2))throw new Error("A repeated timer must have a number above 1 as its repeat count");this.callback=e,this.count=r,this.time=n}get active(){return this.running}static run(e){e.running=!0;let n=0,r;function a(o){if(!e.running)return;r!=null||(r=o);let f=o-r,d=f-p,b=f+p;if(d<e.time&&e.time<b)if(e.running&&e.callback(e instanceof i?n:void 0),n+=1,e instanceof i&&n<e.count)r=void 0;else{e.stop();return}e.frame=window.requestAnimationFrame(a)}e.frame=window.requestAnimationFrame(a)}restart(){return this.stop(),s.run(this),this}start(){return this.running?this:(s.run(this),this)}stop(){return this.running=!1,typeof this.frame=="undefined"?this:(window.cancelAnimationFrame(this.frame),this.frame=void 0,this)}},i=class extends s{},l=class extends s{constructor(e,n){super(e,n,1)}};function C(t,e,n){return new i(t,e,n).start()}function x(t,e){return new l(t,e).start()}
|
|
2
|
+
//# sourceMappingURL=timer.cjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["type RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\nconst milliseconds = Math.round(1000 / 60);\n\nabstract class Timed<Callback> {\n\tprivate readonly callback: Callback;\n\tprivate readonly count: number;\n\tprivate frame: number | undefined;\n\tprivate running = false;\n\tprivate readonly time: number;\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.running;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number) {\n\t\tconst isRepeated = this instanceof Repeated;\n\t\tconst type = isRepeated ? 'repeated' : 'waited';\n\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error(`A ${type} timer must have a callback function`);\n\t\t}\n\n\t\tif (typeof time !== 'number' || time < 0) {\n\t\t\tthrow new Error(`A ${type} timer must have a non-negative number as its time`);\n\t\t}\n\n\t\tif (isRepeated && (typeof count !== 'number' || count < 2)) {\n\t\t\tthrow new Error('A repeated timer must have a number above 1 as its repeat count');\n\t\t}\n\n\t\tthis.callback = callback;\n\t\tthis.count = count;\n\t\tthis.time = time;\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.running = true;\n\n\t\tlet count = 0;\n\n\t\tlet start: DOMHighResTimeStamp | undefined;\n\n\t\tfunction step(timestamp: DOMHighResTimeStamp): void {\n\t\t\tif (!timed.running) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstart ??= timestamp;\n\n\t\t\tconst elapsed = timestamp - start;\n\n\t\t\tconst elapsedMinimum = elapsed - milliseconds;\n\t\t\tconst elapsedMaximum = elapsed + milliseconds;\n\n\t\t\tif (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {\n\t\t\t\tif (timed.running) {\n\t\t\t\t\ttimed.callback(timed instanceof Repeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif ((timed instanceof Repeated) && count < timed.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\n\t\t\t\t\ttimed.stop();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimed.frame = window.requestAnimationFrame(step);\n\t\t}\n\n\t\ttimed.frame = window.requestAnimationFrame(step);\n\t}\n\n\t/**\n\t * Restart timer\n\t */\n\trestart(): this {\n\t\tthis.stop();\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start timer\n\t */\n\tstart(): this {\n\t\tif (this.running) {\n\t\t\treturn this;\n\t\t}\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.running = false;\n\n\t\tif (typeof this.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\twindow.cancelAnimationFrame(this.frame);\n\n\t\tthis.frame = undefined;\n\n\t\treturn this;\n\t}\n}\n\n/**\n * A repeated timer\n */\nexport class Repeated extends Timed<RepeatedCallback> {}\n\n/**\n * A waited timer\n */\nexport class Waited extends Timed<WaitedCallback> {\n\tconstructor(callback: WaitedCallback, time: number) {\n\t\tsuper(callback, time, 1);\n\t}\n}\n\n/**\n * Create and start a new repeated timer\n */\nexport function repeat(callback: RepeatedCallback, time: number, count: number): Repeated {\n\treturn (new Repeated(callback, time, count)).start();\n}\n\n/**\n * Create and start a new waited timer\n */\nexport function wait(callback: WaitedCallback, time: number): Waited {\n\treturn (new Waited(callback, time)).start();\n}\n"],
|
|
5
|
+
"mappings": "qjBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,EAAA,WAAAC,EAAA,WAAAC,EAAA,SAAAC,IAAA,eAAAC,EAAAN,GAGA,IAAMO,EAAe,KAAK,MAAM,kBAAS,EAE1BC,EAAf,KAA+B,CAc9B,YAAYC,EAAoBC,EAAcC,EAAe,CAb7DC,EAAA,KAAiB,YACjBA,EAAA,KAAiB,SACjBA,EAAA,KAAQ,SACRA,EAAA,KAAQ,UAAU,IAClBA,EAAA,KAAiB,QAUhB,IAAMC,EAAa,gBAAgBC,EAC7BC,EAAOF,EAAa,WAAa,SAEvC,GAAI,OAAOJ,GAAa,WACvB,MAAM,IAAI,MAAM,KAAKM,uCAA0C,EAGhE,GAAI,OAAOL,GAAS,UAAYA,EAAO,EACtC,MAAM,IAAI,MAAM,KAAKK,qDAAwD,EAG9E,GAAIF,IAAe,OAAOF,GAAU,UAAYA,EAAQ,GACvD,MAAM,IAAI,MAAM,iEAAiE,EAGlF,KAAK,SAAWF,EAChB,KAAK,MAAQE,EACb,KAAK,KAAOD,CACb,CAvBA,IAAI,QAAkB,CACrB,OAAO,KAAK,OACb,CAuBA,OAAe,IAAIM,EAAyD,CAC3EA,EAAM,QAAU,GAEhB,IAAIL,EAAQ,EAERM,EAEJ,SAASC,EAAKC,EAAsC,CACnD,GAAI,CAACH,EAAM,QACV,OAGDC,GAAA,OAAAA,EAAUE,GAEV,IAAMC,EAAUD,EAAYF,EAEtBI,EAAiBD,EAAUb,EAC3Be,EAAiBF,EAAUb,EAEjC,GAAIc,EAAiBL,EAAM,MAAQA,EAAM,KAAOM,EAO/C,GANIN,EAAM,SACTA,EAAM,SAASA,aAAiBF,EAAWH,EAAQ,MAAS,EAG7DA,GAAS,EAEJK,aAAiBF,GAAaH,EAAQK,EAAM,MAChDC,EAAQ,WACF,CACND,EAAM,KAAK,EAEX,MACD,CAGDA,EAAM,MAAQ,OAAO,sBAAsBE,CAAI,CAChD,CAEAF,EAAM,MAAQ,OAAO,sBAAsBE,CAAI,CAChD,CAKA,SAAgB,CACf,YAAK,KAAK,EAEVV,EAAM,IAAI,IAAa,EAEhB,IACR,CAKA,OAAc,CACb,OAAI,KAAK,QACD,MAGRA,EAAM,IAAI,IAAa,EAEhB,KACR,CAKA,MAAa,CAGZ,OAFA,KAAK,QAAU,GAEX,OAAO,KAAK,OAAU,YAClB,MAGR,OAAO,qBAAqB,KAAK,KAAK,EAEtC,KAAK,MAAQ,OAEN,KACR,CACD,EAKaM,EAAN,cAAuBN,CAAwB,CAAC,EAK1Ce,EAAN,cAAqBf,CAAsB,CACjD,YAAYC,EAA0BC,EAAc,CACnD,MAAMD,EAAUC,EAAM,CAAC,CACxB,CACD,EAKO,SAASc,EAAOf,EAA4BC,EAAcC,EAAyB,CACzF,OAAQ,IAAIG,EAASL,EAAUC,EAAMC,CAAK,EAAG,MAAM,CACpD,CAKO,SAASc,EAAKhB,EAA0BC,EAAsB,CACpE,OAAQ,IAAIa,EAAOd,EAAUC,CAAI,EAAG,MAAM,CAC3C",
|
|
6
|
+
"names": ["src_exports", "__export", "Repeated", "Waited", "repeat", "wait", "__toCommonJS", "milliseconds", "Timed", "callback", "time", "count", "__publicField", "isRepeated", "Repeated", "type", "timed", "start", "step", "timestamp", "elapsed", "elapsedMinimum", "elapsedMaximum", "Waited", "repeat", "wait"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var Timer=(()=>{var c=Object.defineProperty;var h=Object.getOwnPropertyDescriptor;var m=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var w=(t,e,n)=>e in t?c(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n;var k=(t,e)=>{for(var n in e)c(t,n,{get:e[n],enumerable:!0})},g=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of m(e))!v.call(t,a)&&a!==n&&c(t,a,{get:()=>e[a],enumerable:!(r=h(e,a))||r.enumerable});return t};var y=t=>g(c({},"__esModule",{value:!0}),t);var u=(t,e,n)=>(w(t,typeof e!="symbol"?e+"":e,n),n);var A={};k(A,{Repeated:()=>i,Waited:()=>l,repeat:()=>C,wait:()=>x});var p=Math.round(16.666666666666668),s=class{constructor(e,n,r){u(this,"callback");u(this,"count");u(this,"frame");u(this,"running",!1);u(this,"time");let a=this instanceof i,o=a?"repeated":"waited";if(typeof e!="function")throw new Error(`A ${o} timer must have a callback function`);if(typeof n!="number"||n<0)throw new Error(`A ${o} timer must have a non-negative number as its time`);if(a&&(typeof r!="number"||r<2))throw new Error("A repeated timer must have a number above 1 as its repeat count");this.callback=e,this.count=r,this.time=n}get active(){return this.running}static run(e){e.running=!0;let n=0,r;function a(o){if(!e.running)return;r!=null||(r=o);let f=o-r,d=f-p,b=f+p;if(d<e.time&&e.time<b)if(e.running&&e.callback(e instanceof i?n:void 0),n+=1,e instanceof i&&n<e.count)r=void 0;else{e.stop();return}e.frame=window.requestAnimationFrame(a)}e.frame=window.requestAnimationFrame(a)}restart(){return this.stop(),s.run(this),this}start(){return this.running?this:(s.run(this),this)}stop(){return this.running=!1,typeof this.frame=="undefined"?this:(window.cancelAnimationFrame(this.frame),this.frame=void 0,this)}},i=class extends s{},l=class extends s{constructor(e,n){super(e,n,1)}};function C(t,e,n){return new i(t,e,n).start()}function x(t,e){return new l(t,e).start()}return y(A);})();
|
|
2
|
+
//# sourceMappingURL=timer.iife.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["type RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\nconst milliseconds = Math.round(1000 / 60);\n\nabstract class Timed<Callback> {\n\tprivate readonly callback: Callback;\n\tprivate readonly count: number;\n\tprivate frame: number | undefined;\n\tprivate running = false;\n\tprivate readonly time: number;\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.running;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number) {\n\t\tconst isRepeated = this instanceof Repeated;\n\t\tconst type = isRepeated ? 'repeated' : 'waited';\n\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error(`A ${type} timer must have a callback function`);\n\t\t}\n\n\t\tif (typeof time !== 'number' || time < 0) {\n\t\t\tthrow new Error(`A ${type} timer must have a non-negative number as its time`);\n\t\t}\n\n\t\tif (isRepeated && (typeof count !== 'number' || count < 2)) {\n\t\t\tthrow new Error('A repeated timer must have a number above 1 as its repeat count');\n\t\t}\n\n\t\tthis.callback = callback;\n\t\tthis.count = count;\n\t\tthis.time = time;\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.running = true;\n\n\t\tlet count = 0;\n\n\t\tlet start: DOMHighResTimeStamp | undefined;\n\n\t\tfunction step(timestamp: DOMHighResTimeStamp): void {\n\t\t\tif (!timed.running) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstart ??= timestamp;\n\n\t\t\tconst elapsed = timestamp - start;\n\n\t\t\tconst elapsedMinimum = elapsed - milliseconds;\n\t\t\tconst elapsedMaximum = elapsed + milliseconds;\n\n\t\t\tif (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {\n\t\t\t\tif (timed.running) {\n\t\t\t\t\ttimed.callback(timed instanceof Repeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif ((timed instanceof Repeated) && count < timed.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\n\t\t\t\t\ttimed.stop();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimed.frame = window.requestAnimationFrame(step);\n\t\t}\n\n\t\ttimed.frame = window.requestAnimationFrame(step);\n\t}\n\n\t/**\n\t * Restart timer\n\t */\n\trestart(): this {\n\t\tthis.stop();\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start timer\n\t */\n\tstart(): this {\n\t\tif (this.running) {\n\t\t\treturn this;\n\t\t}\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.running = false;\n\n\t\tif (typeof this.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\twindow.cancelAnimationFrame(this.frame);\n\n\t\tthis.frame = undefined;\n\n\t\treturn this;\n\t}\n}\n\n/**\n * A repeated timer\n */\nexport class Repeated extends Timed<RepeatedCallback> {}\n\n/**\n * A waited timer\n */\nexport class Waited extends Timed<WaitedCallback> {\n\tconstructor(callback: WaitedCallback, time: number) {\n\t\tsuper(callback, time, 1);\n\t}\n}\n\n/**\n * Create and start a new repeated timer\n */\nexport function repeat(callback: RepeatedCallback, time: number, count: number): Repeated {\n\treturn (new Repeated(callback, time, count)).start();\n}\n\n/**\n * Create and start a new waited timer\n */\nexport function wait(callback: WaitedCallback, time: number): Waited {\n\treturn (new Waited(callback, time)).start();\n}\n"],
|
|
5
|
+
"mappings": "qkBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,cAAAE,EAAA,WAAAC,EAAA,WAAAC,EAAA,SAAAC,IAGA,IAAMC,EAAe,KAAK,MAAM,kBAAS,EAE1BC,EAAf,KAA+B,CAc9B,YAAYC,EAAoBC,EAAcC,EAAe,CAb7DC,EAAA,KAAiB,YACjBA,EAAA,KAAiB,SACjBA,EAAA,KAAQ,SACRA,EAAA,KAAQ,UAAU,IAClBA,EAAA,KAAiB,QAUhB,IAAMC,EAAa,gBAAgBC,EAC7BC,EAAOF,EAAa,WAAa,SAEvC,GAAI,OAAOJ,GAAa,WACvB,MAAM,IAAI,MAAM,KAAKM,uCAA0C,EAGhE,GAAI,OAAOL,GAAS,UAAYA,EAAO,EACtC,MAAM,IAAI,MAAM,KAAKK,qDAAwD,EAG9E,GAAIF,IAAe,OAAOF,GAAU,UAAYA,EAAQ,GACvD,MAAM,IAAI,MAAM,iEAAiE,EAGlF,KAAK,SAAWF,EAChB,KAAK,MAAQE,EACb,KAAK,KAAOD,CACb,CAvBA,IAAI,QAAkB,CACrB,OAAO,KAAK,OACb,CAuBA,OAAe,IAAIM,EAAyD,CAC3EA,EAAM,QAAU,GAEhB,IAAIL,EAAQ,EAERM,EAEJ,SAASC,EAAKC,EAAsC,CACnD,GAAI,CAACH,EAAM,QACV,OAGDC,GAAA,OAAAA,EAAUE,GAEV,IAAMC,EAAUD,EAAYF,EAEtBI,EAAiBD,EAAUb,EAC3Be,EAAiBF,EAAUb,EAEjC,GAAIc,EAAiBL,EAAM,MAAQA,EAAM,KAAOM,EAO/C,GANIN,EAAM,SACTA,EAAM,SAASA,aAAiBF,EAAWH,EAAQ,MAAS,EAG7DA,GAAS,EAEJK,aAAiBF,GAAaH,EAAQK,EAAM,MAChDC,EAAQ,WACF,CACND,EAAM,KAAK,EAEX,MACD,CAGDA,EAAM,MAAQ,OAAO,sBAAsBE,CAAI,CAChD,CAEAF,EAAM,MAAQ,OAAO,sBAAsBE,CAAI,CAChD,CAKA,SAAgB,CACf,YAAK,KAAK,EAEVV,EAAM,IAAI,IAAa,EAEhB,IACR,CAKA,OAAc,CACb,OAAI,KAAK,QACD,MAGRA,EAAM,IAAI,IAAa,EAEhB,KACR,CAKA,MAAa,CAGZ,OAFA,KAAK,QAAU,GAEX,OAAO,KAAK,OAAU,YAClB,MAGR,OAAO,qBAAqB,KAAK,KAAK,EAEtC,KAAK,MAAQ,OAEN,KACR,CACD,EAKaM,EAAN,cAAuBN,CAAwB,CAAC,EAK1Ce,EAAN,cAAqBf,CAAsB,CACjD,YAAYC,EAA0BC,EAAc,CACnD,MAAMD,EAAUC,EAAM,CAAC,CACxB,CACD,EAKO,SAASc,EAAOf,EAA4BC,EAAcC,EAAyB,CACzF,OAAQ,IAAIG,EAASL,EAAUC,EAAMC,CAAK,EAAG,MAAM,CACpD,CAKO,SAASc,EAAKhB,EAA0BC,EAAsB,CACpE,OAAQ,IAAIa,EAAOd,EAAUC,CAAI,EAAG,MAAM,CAC3C",
|
|
6
|
+
"names": ["src_exports", "__export", "Repeated", "Waited", "repeat", "wait", "milliseconds", "Timed", "callback", "time", "count", "__publicField", "isRepeated", "Repeated", "type", "timed", "start", "step", "timestamp", "elapsed", "elapsedMinimum", "elapsedMaximum", "Waited", "repeat", "wait"]
|
|
7
|
+
}
|
package/dist/timer.js
CHANGED
|
@@ -1,58 +1,29 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
|
-
var __publicField = (obj, key, value) => {
|
|
5
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
-
return value;
|
|
7
|
-
};
|
|
8
|
-
|
|
9
1
|
// src/index.ts
|
|
10
|
-
var milliseconds = 1e3 / 60;
|
|
2
|
+
var milliseconds = Math.round(1e3 / 60);
|
|
11
3
|
var Timed = class {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
4
|
+
callback;
|
|
5
|
+
count;
|
|
6
|
+
frame;
|
|
7
|
+
running = false;
|
|
8
|
+
time;
|
|
9
|
+
get active() {
|
|
10
|
+
return this.running;
|
|
11
|
+
}
|
|
12
|
+
constructor(callback, time, count) {
|
|
13
|
+
const isRepeated = this instanceof Repeated;
|
|
14
|
+
const type = isRepeated ? "repeated" : "waited";
|
|
19
15
|
if (typeof callback !== "function") {
|
|
20
16
|
throw new Error(`A ${type} timer must have a callback function`);
|
|
21
17
|
}
|
|
22
18
|
if (typeof time !== "number" || time < 0) {
|
|
23
19
|
throw new Error(`A ${type} timer must have a non-negative number as its time`);
|
|
24
20
|
}
|
|
25
|
-
if (
|
|
26
|
-
throw new Error(
|
|
21
|
+
if (isRepeated && (typeof count !== "number" || count < 2)) {
|
|
22
|
+
throw new Error("A repeated timer must have a number above 1 as its repeat count");
|
|
27
23
|
}
|
|
28
|
-
this.type = type;
|
|
29
24
|
this.callback = callback;
|
|
30
|
-
this.time = time;
|
|
31
25
|
this.count = count;
|
|
32
|
-
|
|
33
|
-
get active() {
|
|
34
|
-
return this.running;
|
|
35
|
-
}
|
|
36
|
-
restart() {
|
|
37
|
-
this.stop();
|
|
38
|
-
Timed.run(this);
|
|
39
|
-
return this;
|
|
40
|
-
}
|
|
41
|
-
start() {
|
|
42
|
-
if (this.running) {
|
|
43
|
-
return this;
|
|
44
|
-
}
|
|
45
|
-
Timed.run(this);
|
|
46
|
-
return this;
|
|
47
|
-
}
|
|
48
|
-
stop() {
|
|
49
|
-
this.running = false;
|
|
50
|
-
if (typeof this.frame === "undefined") {
|
|
51
|
-
return this;
|
|
52
|
-
}
|
|
53
|
-
window.cancelAnimationFrame(this.frame);
|
|
54
|
-
this.frame = void 0;
|
|
55
|
-
return this;
|
|
26
|
+
this.time = time;
|
|
56
27
|
}
|
|
57
28
|
static run(timed) {
|
|
58
29
|
timed.running = true;
|
|
@@ -62,16 +33,16 @@ var Timed = class {
|
|
|
62
33
|
if (!timed.running) {
|
|
63
34
|
return;
|
|
64
35
|
}
|
|
65
|
-
start
|
|
36
|
+
start ??= timestamp;
|
|
66
37
|
const elapsed = timestamp - start;
|
|
67
38
|
const elapsedMinimum = elapsed - milliseconds;
|
|
68
39
|
const elapsedMaximum = elapsed + milliseconds;
|
|
69
40
|
if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
|
|
70
41
|
if (timed.running) {
|
|
71
|
-
timed.callback(timed
|
|
42
|
+
timed.callback(timed instanceof Repeated ? count : void 0);
|
|
72
43
|
}
|
|
73
44
|
count += 1;
|
|
74
|
-
if (timed
|
|
45
|
+
if (timed instanceof Repeated && count < timed.count) {
|
|
75
46
|
start = void 0;
|
|
76
47
|
} else {
|
|
77
48
|
timed.stop();
|
|
@@ -82,15 +53,33 @@ var Timed = class {
|
|
|
82
53
|
}
|
|
83
54
|
timed.frame = window.requestAnimationFrame(step);
|
|
84
55
|
}
|
|
56
|
+
restart() {
|
|
57
|
+
this.stop();
|
|
58
|
+
Timed.run(this);
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
start() {
|
|
62
|
+
if (this.running) {
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
Timed.run(this);
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
stop() {
|
|
69
|
+
this.running = false;
|
|
70
|
+
if (typeof this.frame === "undefined") {
|
|
71
|
+
return this;
|
|
72
|
+
}
|
|
73
|
+
window.cancelAnimationFrame(this.frame);
|
|
74
|
+
this.frame = void 0;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
85
77
|
};
|
|
86
78
|
var Repeated = class extends Timed {
|
|
87
|
-
constructor(callback, time, count) {
|
|
88
|
-
super("repeated", callback, time, count);
|
|
89
|
-
}
|
|
90
79
|
};
|
|
91
80
|
var Waited = class extends Timed {
|
|
92
81
|
constructor(callback, time) {
|
|
93
|
-
super(
|
|
82
|
+
super(callback, time, 1);
|
|
94
83
|
}
|
|
95
84
|
};
|
|
96
85
|
function repeat(callback, time, count) {
|
|
@@ -105,3 +94,4 @@ export {
|
|
|
105
94
|
repeat,
|
|
106
95
|
wait
|
|
107
96
|
};
|
|
97
|
+
//# sourceMappingURL=timer.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/index.ts"],
|
|
4
|
+
"sourcesContent": ["type RepeatedCallback = (index: number) => void;\ntype WaitedCallback = () => void;\n\nconst milliseconds = Math.round(1000 / 60);\n\nabstract class Timed<Callback> {\n\tprivate readonly callback: Callback;\n\tprivate readonly count: number;\n\tprivate frame: number | undefined;\n\tprivate running = false;\n\tprivate readonly time: number;\n\n\t/**\n\t * Is the timer active?\n\t */\n\tget active(): boolean {\n\t\treturn this.running;\n\t}\n\n\tconstructor(callback: Callback, time: number,\tcount: number) {\n\t\tconst isRepeated = this instanceof Repeated;\n\t\tconst type = isRepeated ? 'repeated' : 'waited';\n\n\t\tif (typeof callback !== 'function') {\n\t\t\tthrow new Error(`A ${type} timer must have a callback function`);\n\t\t}\n\n\t\tif (typeof time !== 'number' || time < 0) {\n\t\t\tthrow new Error(`A ${type} timer must have a non-negative number as its time`);\n\t\t}\n\n\t\tif (isRepeated && (typeof count !== 'number' || count < 2)) {\n\t\t\tthrow new Error('A repeated timer must have a number above 1 as its repeat count');\n\t\t}\n\n\t\tthis.callback = callback;\n\t\tthis.count = count;\n\t\tthis.time = time;\n\t}\n\n\tprivate static run(timed: Timed<(index: number | undefined) => void>): void {\n\t\ttimed.running = true;\n\n\t\tlet count = 0;\n\n\t\tlet start: DOMHighResTimeStamp | undefined;\n\n\t\tfunction step(timestamp: DOMHighResTimeStamp): void {\n\t\t\tif (!timed.running) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tstart ??= timestamp;\n\n\t\t\tconst elapsed = timestamp - start;\n\n\t\t\tconst elapsedMinimum = elapsed - milliseconds;\n\t\t\tconst elapsedMaximum = elapsed + milliseconds;\n\n\t\t\tif (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {\n\t\t\t\tif (timed.running) {\n\t\t\t\t\ttimed.callback(timed instanceof Repeated ? count : undefined);\n\t\t\t\t}\n\n\t\t\t\tcount += 1;\n\n\t\t\t\tif ((timed instanceof Repeated) && count < timed.count) {\n\t\t\t\t\tstart = undefined;\n\t\t\t\t} else {\n\t\t\t\t\ttimed.stop();\n\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttimed.frame = window.requestAnimationFrame(step);\n\t\t}\n\n\t\ttimed.frame = window.requestAnimationFrame(step);\n\t}\n\n\t/**\n\t * Restart timer\n\t */\n\trestart(): this {\n\t\tthis.stop();\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Start timer\n\t */\n\tstart(): this {\n\t\tif (this.running) {\n\t\t\treturn this;\n\t\t}\n\n\t\tTimed.run(this as never);\n\n\t\treturn this;\n\t}\n\n\t/**\n\t * Stop timer\n\t */\n\tstop(): this {\n\t\tthis.running = false;\n\n\t\tif (typeof this.frame === 'undefined') {\n\t\t\treturn this;\n\t\t}\n\n\t\twindow.cancelAnimationFrame(this.frame);\n\n\t\tthis.frame = undefined;\n\n\t\treturn this;\n\t}\n}\n\n/**\n * A repeated timer\n */\nexport class Repeated extends Timed<RepeatedCallback> {}\n\n/**\n * A waited timer\n */\nexport class Waited extends Timed<WaitedCallback> {\n\tconstructor(callback: WaitedCallback, time: number) {\n\t\tsuper(callback, time, 1);\n\t}\n}\n\n/**\n * Create and start a new repeated timer\n */\nexport function repeat(callback: RepeatedCallback, time: number, count: number): Repeated {\n\treturn (new Repeated(callback, time, count)).start();\n}\n\n/**\n * Create and start a new waited timer\n */\nexport function wait(callback: WaitedCallback, time: number): Waited {\n\treturn (new Waited(callback, time)).start();\n}\n"],
|
|
5
|
+
"mappings": ";AAGA,IAAM,eAAe,KAAK,MAAM,MAAO,EAAE;AAEzC,IAAe,QAAf,MAA+B;AAAA,EACb;AAAA,EACA;AAAA,EACT;AAAA,EACA,UAAU;AAAA,EACD;AAAA,EAKjB,IAAI,SAAkB;AACrB,WAAO,KAAK;AAAA,EACb;AAAA,EAEA,YAAY,UAAoB,MAAc,OAAe;AAC5D,UAAM,aAAa,gBAAgB;AACnC,UAAM,OAAO,aAAa,aAAa;AAEvC,QAAI,OAAO,aAAa,YAAY;AACnC,YAAM,IAAI,MAAM,KAAK,0CAA0C;AAAA,IAChE;AAEA,QAAI,OAAO,SAAS,YAAY,OAAO,GAAG;AACzC,YAAM,IAAI,MAAM,KAAK,wDAAwD;AAAA,IAC9E;AAEA,QAAI,eAAe,OAAO,UAAU,YAAY,QAAQ,IAAI;AAC3D,YAAM,IAAI,MAAM,iEAAiE;AAAA,IAClF;AAEA,SAAK,WAAW;AAChB,SAAK,QAAQ;AACb,SAAK,OAAO;AAAA,EACb;AAAA,EAEA,OAAe,IAAI,OAAyD;AAC3E,UAAM,UAAU;AAEhB,QAAI,QAAQ;AAEZ,QAAI;AAEJ,aAAS,KAAK,WAAsC;AACnD,UAAI,CAAC,MAAM,SAAS;AACnB;AAAA,MACD;AAEA,gBAAU;AAEV,YAAM,UAAU,YAAY;AAE5B,YAAM,iBAAiB,UAAU;AACjC,YAAM,iBAAiB,UAAU;AAEjC,UAAI,iBAAiB,MAAM,QAAQ,MAAM,OAAO,gBAAgB;AAC/D,YAAI,MAAM,SAAS;AAClB,gBAAM,SAAS,iBAAiB,WAAW,QAAQ,MAAS;AAAA,QAC7D;AAEA,iBAAS;AAET,YAAK,iBAAiB,YAAa,QAAQ,MAAM,OAAO;AACvD,kBAAQ;AAAA,QACT,OAAO;AACN,gBAAM,KAAK;AAEX;AAAA,QACD;AAAA,MACD;AAEA,YAAM,QAAQ,OAAO,sBAAsB,IAAI;AAAA,IAChD;AAEA,UAAM,QAAQ,OAAO,sBAAsB,IAAI;AAAA,EAChD;AAAA,EAKA,UAAgB;AACf,SAAK,KAAK;AAEV,UAAM,IAAI,IAAa;AAEvB,WAAO;AAAA,EACR;AAAA,EAKA,QAAc;AACb,QAAI,KAAK,SAAS;AACjB,aAAO;AAAA,IACR;AAEA,UAAM,IAAI,IAAa;AAEvB,WAAO;AAAA,EACR;AAAA,EAKA,OAAa;AACZ,SAAK,UAAU;AAEf,QAAI,OAAO,KAAK,UAAU,aAAa;AACtC,aAAO;AAAA,IACR;AAEA,WAAO,qBAAqB,KAAK,KAAK;AAEtC,SAAK,QAAQ;AAEb,WAAO;AAAA,EACR;AACD;AAKO,IAAM,WAAN,cAAuB,MAAwB;AAAC;AAKhD,IAAM,SAAN,cAAqB,MAAsB;AAAA,EACjD,YAAY,UAA0B,MAAc;AACnD,UAAM,UAAU,MAAM,CAAC;AAAA,EACxB;AACD;AAKO,SAAS,OAAO,UAA4B,MAAc,OAAyB;AACzF,SAAQ,IAAI,SAAS,UAAU,MAAM,KAAK,EAAG,MAAM;AACpD;AAKO,SAAS,KAAK,UAA0B,MAAsB;AACpE,SAAQ,IAAI,OAAO,UAAU,IAAI,EAAG,MAAM;AAC3C;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -3,25 +3,31 @@
|
|
|
3
3
|
"name": "Oscar Palmér",
|
|
4
4
|
"url": "https://oscarpalmer.se"
|
|
5
5
|
},
|
|
6
|
-
"
|
|
6
|
+
"browser": "dist/timer.iife.js",
|
|
7
|
+
"description": "A better solution for timeout- and interval-based timers.",
|
|
7
8
|
"devDependencies": {
|
|
8
9
|
"@tsconfig/recommended": "^1.0.0",
|
|
9
|
-
"@types/node": "^18.
|
|
10
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
11
|
-
"@typescript-eslint/parser": "^5.
|
|
12
|
-
"esbuild": "^0.
|
|
13
|
-
"eslint": "^8.
|
|
14
|
-
"eslint-config-xo": "^0.
|
|
15
|
-
"eslint-config-xo-typescript": "^0.
|
|
16
|
-
"typescript": "^4.
|
|
10
|
+
"@types/node": "^18.7.0",
|
|
11
|
+
"@typescript-eslint/eslint-plugin": "^5.36.0",
|
|
12
|
+
"@typescript-eslint/parser": "^5.36.0",
|
|
13
|
+
"esbuild": "^0.15.0",
|
|
14
|
+
"eslint": "^8.23.0",
|
|
15
|
+
"eslint-config-xo": "^0.42.0",
|
|
16
|
+
"eslint-config-xo-typescript": "^0.53.0",
|
|
17
|
+
"typescript": "^4.8.0"
|
|
17
18
|
},
|
|
18
19
|
"exports": {
|
|
19
20
|
".": {
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
"types": "./src/index.d.ts",
|
|
22
|
+
"browser": "./dist/timer.iife.js",
|
|
23
|
+
"module": "./dist/timer.js",
|
|
24
|
+
"import": "./dist/timer.js",
|
|
25
|
+
"require": "./dist/timer.cjs"
|
|
26
|
+
},
|
|
27
|
+
"./package.json": "./package.json"
|
|
23
28
|
},
|
|
24
|
-
"
|
|
29
|
+
"files": ["dist", "src"],
|
|
30
|
+
"jsdelivr": "dist/timer.iife.js",
|
|
25
31
|
"keywords": [
|
|
26
32
|
"timer",
|
|
27
33
|
"setTimeout",
|
|
@@ -29,7 +35,7 @@
|
|
|
29
35
|
"requestAnimationFrame"
|
|
30
36
|
],
|
|
31
37
|
"license": "MIT",
|
|
32
|
-
"main": "dist/timer.
|
|
38
|
+
"main": "dist/timer.cjs",
|
|
33
39
|
"module": "dist/timer.js",
|
|
34
40
|
"name": "@oscarpalmer/timer",
|
|
35
41
|
"repository": {
|
|
@@ -37,11 +43,14 @@
|
|
|
37
43
|
"url": "git+https://github.com/oscarpalmer/timer.git"
|
|
38
44
|
},
|
|
39
45
|
"scripts": {
|
|
40
|
-
"build": "
|
|
41
|
-
"
|
|
46
|
+
"build": "npm run build:cjs; npm run build:esm; npm run build:iife",
|
|
47
|
+
"build:cjs": "esbuild ./src/index.ts --bundle --minify --sourcemap --format=cjs --outfile=./dist/timer.cjs --target=es2017",
|
|
48
|
+
"build:esm": "esbuild ./src/index.ts --bundle --sourcemap --format=esm --outfile=./dist/timer.js --target=esnext",
|
|
49
|
+
"build:iife": "esbuild ./src/index.ts --bundle --minify --sourcemap --format=iife --global-name=Timer --outfile=./dist/timer.iife.js --target=es2017",
|
|
50
|
+
"watch": "esbuild ./src/index.ts --bundle --watch --format=esm --outfile=./dist/timer.js --platform=browser --target=esnext"
|
|
42
51
|
},
|
|
43
52
|
"type": "module",
|
|
44
53
|
"types": "src/index.d.ts",
|
|
45
|
-
"unpkg": "dist/timer.js",
|
|
46
|
-
"version": "0.
|
|
47
|
-
}
|
|
54
|
+
"unpkg": "dist/timer.iife.js",
|
|
55
|
+
"version": "0.9.0"
|
|
56
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
type RepeatedCallback = (index: number) => void;
|
|
2
|
-
type TimerType = 'repeated' | 'waited';
|
|
3
2
|
type WaitedCallback = () => void;
|
|
4
3
|
|
|
5
|
-
const milliseconds = 1000 / 60;
|
|
4
|
+
const milliseconds = Math.round(1000 / 60);
|
|
6
5
|
|
|
7
6
|
abstract class Timed<Callback> {
|
|
8
7
|
private readonly callback: Callback;
|
|
@@ -10,7 +9,6 @@ abstract class Timed<Callback> {
|
|
|
10
9
|
private frame: number | undefined;
|
|
11
10
|
private running = false;
|
|
12
11
|
private readonly time: number;
|
|
13
|
-
private readonly type: TimerType;
|
|
14
12
|
|
|
15
13
|
/**
|
|
16
14
|
* Is the timer active?
|
|
@@ -19,7 +17,10 @@ abstract class Timed<Callback> {
|
|
|
19
17
|
return this.running;
|
|
20
18
|
}
|
|
21
19
|
|
|
22
|
-
|
|
20
|
+
constructor(callback: Callback, time: number, count: number) {
|
|
21
|
+
const isRepeated = this instanceof Repeated;
|
|
22
|
+
const type = isRepeated ? 'repeated' : 'waited';
|
|
23
|
+
|
|
23
24
|
if (typeof callback !== 'function') {
|
|
24
25
|
throw new Error(`A ${type} timer must have a callback function`);
|
|
25
26
|
}
|
|
@@ -28,14 +29,54 @@ abstract class Timed<Callback> {
|
|
|
28
29
|
throw new Error(`A ${type} timer must have a non-negative number as its time`);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
if (
|
|
32
|
-
throw new Error(
|
|
32
|
+
if (isRepeated && (typeof count !== 'number' || count < 2)) {
|
|
33
|
+
throw new Error('A repeated timer must have a number above 1 as its repeat count');
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
this.type = type;
|
|
36
36
|
this.callback = callback;
|
|
37
|
-
this.time = time;
|
|
38
37
|
this.count = count;
|
|
38
|
+
this.time = time;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private static run(timed: Timed<(index: number | undefined) => void>): void {
|
|
42
|
+
timed.running = true;
|
|
43
|
+
|
|
44
|
+
let count = 0;
|
|
45
|
+
|
|
46
|
+
let start: DOMHighResTimeStamp | undefined;
|
|
47
|
+
|
|
48
|
+
function step(timestamp: DOMHighResTimeStamp): void {
|
|
49
|
+
if (!timed.running) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
start ??= timestamp;
|
|
54
|
+
|
|
55
|
+
const elapsed = timestamp - start;
|
|
56
|
+
|
|
57
|
+
const elapsedMinimum = elapsed - milliseconds;
|
|
58
|
+
const elapsedMaximum = elapsed + milliseconds;
|
|
59
|
+
|
|
60
|
+
if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
|
|
61
|
+
if (timed.running) {
|
|
62
|
+
timed.callback(timed instanceof Repeated ? count : undefined);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
count += 1;
|
|
66
|
+
|
|
67
|
+
if ((timed instanceof Repeated) && count < timed.count) {
|
|
68
|
+
start = undefined;
|
|
69
|
+
} else {
|
|
70
|
+
timed.stop();
|
|
71
|
+
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
timed.frame = window.requestAnimationFrame(step);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
timed.frame = window.requestAnimationFrame(step);
|
|
39
80
|
}
|
|
40
81
|
|
|
41
82
|
/**
|
|
@@ -78,64 +119,19 @@ abstract class Timed<Callback> {
|
|
|
78
119
|
|
|
79
120
|
return this;
|
|
80
121
|
}
|
|
81
|
-
|
|
82
|
-
private static run(timed: Timed<(index: number | undefined) => void>): void {
|
|
83
|
-
timed.running = true;
|
|
84
|
-
|
|
85
|
-
let count = 0;
|
|
86
|
-
|
|
87
|
-
let start: DOMHighResTimeStamp | undefined;
|
|
88
|
-
|
|
89
|
-
function step(timestamp: DOMHighResTimeStamp): void {
|
|
90
|
-
if (!timed.running) {
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
start ??= timestamp;
|
|
95
|
-
|
|
96
|
-
const elapsed = timestamp - start;
|
|
97
|
-
|
|
98
|
-
const elapsedMinimum = elapsed - milliseconds;
|
|
99
|
-
const elapsedMaximum = elapsed + milliseconds;
|
|
100
|
-
|
|
101
|
-
if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
|
|
102
|
-
if (timed.running) {
|
|
103
|
-
timed.callback(timed.type === 'repeated' ? count : undefined);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
count += 1;
|
|
107
|
-
|
|
108
|
-
if (timed.type === 'repeated' && count < timed.count) {
|
|
109
|
-
start = undefined;
|
|
110
|
-
} else {
|
|
111
|
-
timed.stop();
|
|
112
|
-
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
timed.frame = window.requestAnimationFrame(step);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
timed.frame = window.requestAnimationFrame(step);
|
|
121
|
-
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/**
|
|
125
125
|
* A repeated timer
|
|
126
126
|
*/
|
|
127
|
-
export class Repeated extends Timed<RepeatedCallback> {
|
|
128
|
-
constructor(callback: RepeatedCallback, time: number, count: number) {
|
|
129
|
-
super('repeated', callback, time, count);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
127
|
+
export class Repeated extends Timed<RepeatedCallback> {}
|
|
132
128
|
|
|
133
129
|
/**
|
|
134
130
|
* A waited timer
|
|
135
131
|
*/
|
|
136
132
|
export class Waited extends Timed<WaitedCallback> {
|
|
137
133
|
constructor(callback: WaitedCallback, time: number) {
|
|
138
|
-
super(
|
|
134
|
+
super(callback, time, 1);
|
|
139
135
|
}
|
|
140
136
|
}
|
|
141
137
|
|
package/.eslintrc.json
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"root": true,
|
|
3
|
-
"extends": [
|
|
4
|
-
"xo",
|
|
5
|
-
"xo-typescript"
|
|
6
|
-
],
|
|
7
|
-
"parser": "@typescript-eslint/parser",
|
|
8
|
-
"parserOptions": {
|
|
9
|
-
"project": [
|
|
10
|
-
"./tsconfig.json"
|
|
11
|
-
]
|
|
12
|
-
},
|
|
13
|
-
"plugins": [
|
|
14
|
-
"@typescript-eslint"
|
|
15
|
-
],
|
|
16
|
-
"rules": {
|
|
17
|
-
"@typescript-eslint/member-ordering": [
|
|
18
|
-
"error",
|
|
19
|
-
{
|
|
20
|
-
"default": [
|
|
21
|
-
"signature",
|
|
22
|
-
|
|
23
|
-
"private-decorated-field", "protected-decorated-field", "public-decorated-field", "decorated-field",
|
|
24
|
-
|
|
25
|
-
"private-static-field", "protected-static-field", "public-static-field", "static-field",
|
|
26
|
-
|
|
27
|
-
["private-abstract-field", "private-instance-field", "private-field"],
|
|
28
|
-
["protected-abstract-field", "protected-instance-field", "protected-field"],
|
|
29
|
-
["public-abstract-field", "public-instance-field", "public-field"],
|
|
30
|
-
["abstract-field", "instance-field", "field"],
|
|
31
|
-
|
|
32
|
-
"private-constructor", "protected-constructor", "public-constructor", "constructor",
|
|
33
|
-
|
|
34
|
-
["public-abstract-method", "public-decorated-method", "public-instance-method", "public-method"],
|
|
35
|
-
["protected-abstract-method", "protected-decorated-method", "protected-instance-method", "protected-method"],
|
|
36
|
-
["private-abstract-method", "private-decorated-method", "private-instance-method", "private-method"],
|
|
37
|
-
["abstract-method", "decorated-method", "instance-method", "method"],
|
|
38
|
-
|
|
39
|
-
"static-method", "public-static-method", "protected-static-method", "private-static-method"
|
|
40
|
-
]
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
}
|
|
44
|
-
}
|
package/test/index.html
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="utf-8" />
|
|
5
|
-
<title>Mocha Tests</title>
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
-
<link rel="stylesheet" href="https://unpkg.com/mocha/mocha.css" />
|
|
8
|
-
</head>
|
|
9
|
-
<body>
|
|
10
|
-
<div id="mocha"></div>
|
|
11
|
-
|
|
12
|
-
<script src="https://unpkg.com/chai/chai.js"></script>
|
|
13
|
-
<script src="https://unpkg.com/mocha/mocha.js"></script>
|
|
14
|
-
|
|
15
|
-
<script class="mocha-init">
|
|
16
|
-
mocha.setup('bdd');
|
|
17
|
-
mocha.checkLeaks();
|
|
18
|
-
</script>
|
|
19
|
-
<script src="test/test.js" type="module"></script>
|
|
20
|
-
<script class="mocha-exec">
|
|
21
|
-
mocha.run();
|
|
22
|
-
</script>
|
|
23
|
-
</body>
|
|
24
|
-
</html>
|
package/test/test.js
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import {repeat, wait, Repeated, Waited} from '../dist/timer.js';
|
|
2
|
-
|
|
3
|
-
describe('Functions', function () {
|
|
4
|
-
it('should create and start a repeated timer', function () {
|
|
5
|
-
chai.assert.ok(repeat(() => {}, 0, 2) instanceof Repeated);
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
it('should create and start a waited timer', function () {
|
|
9
|
-
chai.assert.ok(wait(() => {}, 0) instanceof Waited);
|
|
10
|
-
});
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
describe('Timer, Repeated', function () {
|
|
14
|
-
describe('Constructor', function () {
|
|
15
|
-
it('should create a proper repeated timer', function () {
|
|
16
|
-
chai.assert.ok(new Repeated(() => {}, 0, 2) instanceof Repeated);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
it('should handle bad parameters', function () {
|
|
20
|
-
chai.assert.throws(function () { new Repeated(null, null, null); }, /callback/);
|
|
21
|
-
chai.assert.throws(function () { new Repeated(() => {}, null, null); }, /time/);
|
|
22
|
-
chai.assert.throws(function () { new Repeated(() => {}, 0, null); }, /count/);
|
|
23
|
-
chai.assert.throws(function () { new Repeated(() => {}, 0, 1); }, /count/);
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
describe('Run', function () {
|
|
28
|
-
it('should run as many times as set', function (done) {
|
|
29
|
-
let value = 0;
|
|
30
|
-
|
|
31
|
-
repeat(() => {
|
|
32
|
-
value += 1;
|
|
33
|
-
}, 25, 10);
|
|
34
|
-
|
|
35
|
-
wait(() => {
|
|
36
|
-
chai.assert.equal(value, 10);
|
|
37
|
-
|
|
38
|
-
done();
|
|
39
|
-
}, 500);
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it('should run until canceled', function (done) {
|
|
43
|
-
let value = 0;
|
|
44
|
-
|
|
45
|
-
const repeated = repeat(() => {
|
|
46
|
-
value += 1;
|
|
47
|
-
}, 25, 10);
|
|
48
|
-
|
|
49
|
-
wait(() => {
|
|
50
|
-
repeated.stop();
|
|
51
|
-
}, 125);
|
|
52
|
-
|
|
53
|
-
wait(() => {
|
|
54
|
-
chai.assert.ok(value < 10);
|
|
55
|
-
|
|
56
|
-
done();
|
|
57
|
-
}, 500);
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
describe('Timer, Waited', function () {
|
|
63
|
-
describe('Constructor', function () {
|
|
64
|
-
it('should create a proper waited timer', function () {
|
|
65
|
-
chai.assert.ok(new Waited(() => {}, 0));
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
it('should handle bad parameters', function () {
|
|
69
|
-
chai.assert.throws(function () { new Waited(null, null); }, /callback/);
|
|
70
|
-
chai.assert.throws(function () { new Waited(() => {}, null); }, /time/);
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
describe('Timer, Repeated & Waited', function () {
|
|
76
|
-
describe('Methods', function () {
|
|
77
|
-
it('should be able to start', function (done) {
|
|
78
|
-
(new Waited(() => {
|
|
79
|
-
done();
|
|
80
|
-
}, 125)).start();
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('should be able to stop', function (done) {
|
|
84
|
-
let value = 0;
|
|
85
|
-
|
|
86
|
-
const waited = new Waited(() => {
|
|
87
|
-
value = 1234;
|
|
88
|
-
}, 125);
|
|
89
|
-
|
|
90
|
-
wait(() => {
|
|
91
|
-
waited.stop();
|
|
92
|
-
}, 250);
|
|
93
|
-
|
|
94
|
-
wait(() => {
|
|
95
|
-
chai.assert.equal(value, 0);
|
|
96
|
-
|
|
97
|
-
done();
|
|
98
|
-
}, 375);
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
it('should be able to restart', function (done) {
|
|
102
|
-
let value = 0;
|
|
103
|
-
|
|
104
|
-
const waited = new Waited(() => {
|
|
105
|
-
value += 1;
|
|
106
|
-
}, 125);
|
|
107
|
-
|
|
108
|
-
waited.start();
|
|
109
|
-
|
|
110
|
-
wait(() => {
|
|
111
|
-
waited.restart();
|
|
112
|
-
}, 250);
|
|
113
|
-
|
|
114
|
-
wait(() => {
|
|
115
|
-
chai.assert.equal(value, 2);
|
|
116
|
-
|
|
117
|
-
done();
|
|
118
|
-
}, 500);
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
});
|
package/tsconfig.json
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"allowSyntheticDefaultImports": true,
|
|
4
|
-
"declaration": true,
|
|
5
|
-
"forceConsistentCasingInFileNames": true,
|
|
6
|
-
"lib": [
|
|
7
|
-
"DOM",
|
|
8
|
-
"DOM.Iterable",
|
|
9
|
-
"ES2020"
|
|
10
|
-
],
|
|
11
|
-
"newLine": "lf",
|
|
12
|
-
"noEmitOnError": true,
|
|
13
|
-
"noFallthroughCasesInSwitch": true,
|
|
14
|
-
"noImplicitOverride": true,
|
|
15
|
-
"noImplicitReturns": true,
|
|
16
|
-
"noPropertyAccessFromIndexSignature": true,
|
|
17
|
-
"noUncheckedIndexedAccess": true,
|
|
18
|
-
"noUnusedLocals": true,
|
|
19
|
-
"noUnusedParameters": true,
|
|
20
|
-
"preserveConstEnums": true,
|
|
21
|
-
"pretty": true,
|
|
22
|
-
"resolveJsonModule": false,
|
|
23
|
-
"skipLibCheck": true,
|
|
24
|
-
"strict": true,
|
|
25
|
-
"stripInternal": true,
|
|
26
|
-
"target": "ES2020",
|
|
27
|
-
"useDefineForClassFields": true
|
|
28
|
-
},
|
|
29
|
-
"include": ["src/**/*.ts"],
|
|
30
|
-
"exclude": ["src/**/*.d.ts", "dist", "node_modules"]
|
|
31
|
-
}
|