@oscarpalmer/timer 0.5.0 → 0.8.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 +42 -2
- package/dist/timer.cjs.js +125 -0
- package/dist/timer.iife.js +127 -0
- package/dist/timer.js +10 -12
- package/package.json +23 -14
- package/src/index.d.ts +1 -18
- package/.eslintrc.json +0 -44
- package/src/index.ts +0 -132
- package/test/index.html +0 -24
- package/test/test.js +0 -121
- package/tsconfig.json +0 -31
package/README.md
CHANGED
|
@@ -1,7 +1,47 @@
|
|
|
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).
|
|
10
|
+
|
|
11
|
+
## Getting started
|
|
12
|
+
|
|
13
|
+
This is fairly lightweight package, so hopefully you'll be up and running in seconds :blush:
|
|
14
|
+
|
|
15
|
+
### Examples
|
|
16
|
+
|
|
17
|
+
The timers can be called with nice helper methods, which also auto-starts the timers:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import {repeat, wait} from '@oscarpalmer/timer';
|
|
21
|
+
|
|
22
|
+
let waited = wait(callback, time);
|
|
23
|
+
let repeated = repeat(callback, time, count);
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or they can be created using class syntax, but without being auto-started:
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import {Repeated, Waited} from '@oscarpalmer/timer';
|
|
30
|
+
|
|
31
|
+
waited = new Waited(callback, time);
|
|
32
|
+
repeated = new Repeated(callback, time, count);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Methods
|
|
36
|
+
|
|
37
|
+
Both the nice helper methods and the class syntax create similar objects – `Waited` and `Repeated` – which share methods:
|
|
38
|
+
|
|
39
|
+
|Method|Description|
|
|
40
|
+
|-----:|:----------|
|
|
41
|
+
|`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|
|
|
42
|
+
|`stop()`|Stops the timer|
|
|
43
|
+
|`restart()`|Restarts the timer|
|
|
4
44
|
|
|
5
45
|
## License
|
|
6
46
|
|
|
7
|
-
[
|
|
47
|
+
[MIT licensed](LICENSE), natch :wink:
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
var __publicField = (obj, key, value) => {
|
|
21
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
22
|
+
return value;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
// src/index.ts
|
|
26
|
+
var src_exports = {};
|
|
27
|
+
__export(src_exports, {
|
|
28
|
+
Repeated: () => Repeated,
|
|
29
|
+
Waited: () => Waited,
|
|
30
|
+
repeat: () => repeat,
|
|
31
|
+
wait: () => wait
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(src_exports);
|
|
34
|
+
var milliseconds = Math.round(1e3 / 60);
|
|
35
|
+
var Timed = class {
|
|
36
|
+
constructor(type, callback, time, count) {
|
|
37
|
+
__publicField(this, "callback");
|
|
38
|
+
__publicField(this, "count");
|
|
39
|
+
__publicField(this, "frame");
|
|
40
|
+
__publicField(this, "running", false);
|
|
41
|
+
__publicField(this, "time");
|
|
42
|
+
__publicField(this, "type");
|
|
43
|
+
if (typeof callback !== "function") {
|
|
44
|
+
throw new Error(`A ${type} timer must have a callback function`);
|
|
45
|
+
}
|
|
46
|
+
if (typeof time !== "number" || time < 0) {
|
|
47
|
+
throw new Error(`A ${type} timer must have a non-negative number as its time`);
|
|
48
|
+
}
|
|
49
|
+
if (type === "repeated" && (typeof count !== "number" || count < 2)) {
|
|
50
|
+
throw new Error(`A ${type} timer must have a number above 1 as its repeat count`);
|
|
51
|
+
}
|
|
52
|
+
this.type = type;
|
|
53
|
+
this.callback = callback;
|
|
54
|
+
this.time = time;
|
|
55
|
+
this.count = count;
|
|
56
|
+
}
|
|
57
|
+
get active() {
|
|
58
|
+
return this.running;
|
|
59
|
+
}
|
|
60
|
+
restart() {
|
|
61
|
+
this.stop();
|
|
62
|
+
Timed.run(this);
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
start() {
|
|
66
|
+
if (this.running) {
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
Timed.run(this);
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
stop() {
|
|
73
|
+
this.running = false;
|
|
74
|
+
if (typeof this.frame === "undefined") {
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
window.cancelAnimationFrame(this.frame);
|
|
78
|
+
this.frame = void 0;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
static run(timed) {
|
|
82
|
+
timed.running = true;
|
|
83
|
+
let count = 0;
|
|
84
|
+
let start;
|
|
85
|
+
function step(timestamp) {
|
|
86
|
+
if (!timed.running) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
start ?? (start = timestamp);
|
|
90
|
+
const elapsed = timestamp - start;
|
|
91
|
+
const elapsedMinimum = elapsed - milliseconds;
|
|
92
|
+
const elapsedMaximum = elapsed + milliseconds;
|
|
93
|
+
if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
|
|
94
|
+
if (timed.running) {
|
|
95
|
+
timed.callback(timed.type === "repeated" ? count : void 0);
|
|
96
|
+
}
|
|
97
|
+
count += 1;
|
|
98
|
+
if (timed.type === "repeated" && count < timed.count) {
|
|
99
|
+
start = void 0;
|
|
100
|
+
} else {
|
|
101
|
+
timed.stop();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
timed.frame = window.requestAnimationFrame(step);
|
|
106
|
+
}
|
|
107
|
+
timed.frame = window.requestAnimationFrame(step);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
var Repeated = class extends Timed {
|
|
111
|
+
constructor(callback, time, count) {
|
|
112
|
+
super("repeated", callback, time, count);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
var Waited = class extends Timed {
|
|
116
|
+
constructor(callback, time) {
|
|
117
|
+
super("waited", callback, time, 1);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
function repeat(callback, time, count) {
|
|
121
|
+
return new Repeated(callback, time, count).start();
|
|
122
|
+
}
|
|
123
|
+
function wait(callback, time) {
|
|
124
|
+
return new Waited(callback, time).start();
|
|
125
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var Timer = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
var __publicField = (obj, key, value) => {
|
|
22
|
+
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
23
|
+
return value;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var src_exports = {};
|
|
28
|
+
__export(src_exports, {
|
|
29
|
+
Repeated: () => Repeated,
|
|
30
|
+
Waited: () => Waited,
|
|
31
|
+
repeat: () => repeat,
|
|
32
|
+
wait: () => wait
|
|
33
|
+
});
|
|
34
|
+
var milliseconds = Math.round(1e3 / 60);
|
|
35
|
+
var Timed = class {
|
|
36
|
+
constructor(type, callback, time, count) {
|
|
37
|
+
__publicField(this, "callback");
|
|
38
|
+
__publicField(this, "count");
|
|
39
|
+
__publicField(this, "frame");
|
|
40
|
+
__publicField(this, "running", false);
|
|
41
|
+
__publicField(this, "time");
|
|
42
|
+
__publicField(this, "type");
|
|
43
|
+
if (typeof callback !== "function") {
|
|
44
|
+
throw new Error(`A ${type} timer must have a callback function`);
|
|
45
|
+
}
|
|
46
|
+
if (typeof time !== "number" || time < 0) {
|
|
47
|
+
throw new Error(`A ${type} timer must have a non-negative number as its time`);
|
|
48
|
+
}
|
|
49
|
+
if (type === "repeated" && (typeof count !== "number" || count < 2)) {
|
|
50
|
+
throw new Error(`A ${type} timer must have a number above 1 as its repeat count`);
|
|
51
|
+
}
|
|
52
|
+
this.type = type;
|
|
53
|
+
this.callback = callback;
|
|
54
|
+
this.time = time;
|
|
55
|
+
this.count = count;
|
|
56
|
+
}
|
|
57
|
+
get active() {
|
|
58
|
+
return this.running;
|
|
59
|
+
}
|
|
60
|
+
restart() {
|
|
61
|
+
this.stop();
|
|
62
|
+
Timed.run(this);
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
start() {
|
|
66
|
+
if (this.running) {
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
Timed.run(this);
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
stop() {
|
|
73
|
+
this.running = false;
|
|
74
|
+
if (typeof this.frame === "undefined") {
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
77
|
+
window.cancelAnimationFrame(this.frame);
|
|
78
|
+
this.frame = void 0;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
static run(timed) {
|
|
82
|
+
timed.running = true;
|
|
83
|
+
let count = 0;
|
|
84
|
+
let start;
|
|
85
|
+
function step(timestamp) {
|
|
86
|
+
if (!timed.running) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
start ?? (start = timestamp);
|
|
90
|
+
const elapsed = timestamp - start;
|
|
91
|
+
const elapsedMinimum = elapsed - milliseconds;
|
|
92
|
+
const elapsedMaximum = elapsed + milliseconds;
|
|
93
|
+
if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
|
|
94
|
+
if (timed.running) {
|
|
95
|
+
timed.callback(timed.type === "repeated" ? count : void 0);
|
|
96
|
+
}
|
|
97
|
+
count += 1;
|
|
98
|
+
if (timed.type === "repeated" && count < timed.count) {
|
|
99
|
+
start = void 0;
|
|
100
|
+
} else {
|
|
101
|
+
timed.stop();
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
timed.frame = window.requestAnimationFrame(step);
|
|
106
|
+
}
|
|
107
|
+
timed.frame = window.requestAnimationFrame(step);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
var Repeated = class extends Timed {
|
|
111
|
+
constructor(callback, time, count) {
|
|
112
|
+
super("repeated", callback, time, count);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
var Waited = class extends Timed {
|
|
116
|
+
constructor(callback, time) {
|
|
117
|
+
super("waited", callback, time, 1);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
function repeat(callback, time, count) {
|
|
121
|
+
return new Repeated(callback, time, count).start();
|
|
122
|
+
}
|
|
123
|
+
function wait(callback, time) {
|
|
124
|
+
return new Waited(callback, time).start();
|
|
125
|
+
}
|
|
126
|
+
return __toCommonJS(src_exports);
|
|
127
|
+
})();
|
package/dist/timer.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
var __defProp = Object.defineProperty;
|
|
3
2
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
4
3
|
var __publicField = (obj, key, value) => {
|
|
@@ -7,7 +6,7 @@ var __publicField = (obj, key, value) => {
|
|
|
7
6
|
};
|
|
8
7
|
|
|
9
8
|
// src/index.ts
|
|
10
|
-
var milliseconds = 1e3 / 60;
|
|
9
|
+
var milliseconds = Math.round(1e3 / 60);
|
|
11
10
|
var Timed = class {
|
|
12
11
|
constructor(type, callback, time, count) {
|
|
13
12
|
__publicField(this, "callback");
|
|
@@ -93,16 +92,15 @@ var Waited = class extends Timed {
|
|
|
93
92
|
super("waited", callback, time, 1);
|
|
94
93
|
}
|
|
95
94
|
};
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
};
|
|
95
|
+
function repeat(callback, time, count) {
|
|
96
|
+
return new Repeated(callback, time, count).start();
|
|
97
|
+
}
|
|
98
|
+
function wait(callback, time) {
|
|
99
|
+
return new Waited(callback, time).start();
|
|
100
|
+
}
|
|
104
101
|
export {
|
|
105
102
|
Repeated,
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
Waited,
|
|
104
|
+
repeat,
|
|
105
|
+
wait
|
|
108
106
|
};
|
package/package.json
CHANGED
|
@@ -3,24 +3,30 @@
|
|
|
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
|
".": {
|
|
21
|
+
"types": "./src/index.d.ts",
|
|
22
|
+
"script": "./dist/timer.iife.js",
|
|
23
|
+
"module": "./dist/timer.js",
|
|
20
24
|
"import": "./dist/timer.js",
|
|
21
|
-
"require": "./dist/timer.js"
|
|
25
|
+
"require": "./dist/timer.cjs.js",
|
|
26
|
+
"default": "./dist/timer.js"
|
|
22
27
|
}
|
|
23
28
|
},
|
|
29
|
+
"files": ["dist", "src/index.d.ts"],
|
|
24
30
|
"jsdelivr": "dist/timer.js",
|
|
25
31
|
"keywords": [
|
|
26
32
|
"timer",
|
|
@@ -29,7 +35,7 @@
|
|
|
29
35
|
"requestAnimationFrame"
|
|
30
36
|
],
|
|
31
37
|
"license": "MIT",
|
|
32
|
-
"main": "dist/timer.js",
|
|
38
|
+
"main": "dist/timer.cjs.js",
|
|
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": "
|
|
46
|
+
"build": "npm run build:cjs; npm run build:esm; npm run build:iife",
|
|
47
|
+
"build:cjs": "esbuild ./src/index.ts --bundle --target=es2020 --platform=browser --outfile=./dist/timer.cjs.js --format=cjs",
|
|
48
|
+
"build:esm": "esbuild ./src/index.ts --bundle --target=es2020 --platform=browser --outfile=./dist/timer.js --format=esm",
|
|
49
|
+
"build:iife": "esbuild ./src/index.ts --bundle --target=es2020 --platform=browser --outfile=./dist/timer.iife.js --format=iife --global-name=Timer",
|
|
41
50
|
"watch": "esbuild ./src/index.ts --bundle --target=es2020 --platform=browser --outfile=./dist/timer.js --format=esm --watch"
|
|
42
51
|
},
|
|
43
52
|
"type": "module",
|
|
44
53
|
"types": "src/index.d.ts",
|
|
45
54
|
"unpkg": "dist/timer.js",
|
|
46
|
-
"version": "0.
|
|
47
|
-
}
|
|
55
|
+
"version": "0.8.0"
|
|
56
|
+
}
|
package/src/index.d.ts
CHANGED
|
@@ -1,18 +1 @@
|
|
|
1
|
-
|
|
2
|
-
type WaitedCallback = () => void;
|
|
3
|
-
|
|
4
|
-
interface Timed<Callback> {
|
|
5
|
-
get active(): boolean;
|
|
6
|
-
constructor(callback: Callback, time: number, count: number): void;
|
|
7
|
-
restart(): void;
|
|
8
|
-
start(): void;
|
|
9
|
-
stop(): void;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface Repeated extends Timed<RepeatedCallback> {}
|
|
13
|
-
export interface Waited extends Timed<WaitedCallback> {}
|
|
14
|
-
|
|
15
|
-
export interface Timer {
|
|
16
|
-
repeated(callback: RepeatedCallback, time: number, count: number): Repeated;
|
|
17
|
-
waited(callback: WaitedCallback, time: number): Waited;
|
|
18
|
-
}
|
|
1
|
+
export * from './index';
|
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/src/index.ts
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
type RepeatedCallback = (index: number) => void;
|
|
2
|
-
type TimerType = 'repeated' | 'waited';
|
|
3
|
-
type WaitedCallback = () => void;
|
|
4
|
-
|
|
5
|
-
const milliseconds = 1000 / 60;
|
|
6
|
-
|
|
7
|
-
abstract class Timed<Callback> {
|
|
8
|
-
private readonly callback: Callback;
|
|
9
|
-
private readonly count: number;
|
|
10
|
-
private frame: number | undefined;
|
|
11
|
-
private running = false;
|
|
12
|
-
private readonly time: number;
|
|
13
|
-
private readonly type: TimerType;
|
|
14
|
-
|
|
15
|
-
get active(): boolean {
|
|
16
|
-
return this.running;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
protected constructor(type: TimerType, callback: Callback, time: number, count: number) {
|
|
20
|
-
if (typeof callback !== 'function') {
|
|
21
|
-
throw new Error(`A ${type} timer must have a callback function`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
if (typeof time !== 'number' || time < 0) {
|
|
25
|
-
throw new Error(`A ${type} timer must have a non-negative number as its time`);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (type === 'repeated' && (typeof count !== 'number' || count < 2)) {
|
|
29
|
-
throw new Error(`A ${type} timer must have a number above 1 as its repeat count`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
this.type = type;
|
|
33
|
-
this.callback = callback;
|
|
34
|
-
this.time = time;
|
|
35
|
-
this.count = count;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
restart(): Timed<Callback> {
|
|
39
|
-
this.stop();
|
|
40
|
-
|
|
41
|
-
Timed.run(this as never);
|
|
42
|
-
|
|
43
|
-
return this;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
start(): Timed<Callback> {
|
|
47
|
-
if (this.running) {
|
|
48
|
-
return this;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
Timed.run(this as never);
|
|
52
|
-
|
|
53
|
-
return this;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
stop(): Timed<Callback> {
|
|
57
|
-
this.running = false;
|
|
58
|
-
|
|
59
|
-
if (typeof this.frame === 'undefined') {
|
|
60
|
-
return this;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
window.cancelAnimationFrame(this.frame);
|
|
64
|
-
|
|
65
|
-
this.frame = undefined;
|
|
66
|
-
|
|
67
|
-
return this;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
private static run(timed: Timed<(index: number | undefined) => void>): void {
|
|
71
|
-
timed.running = true;
|
|
72
|
-
|
|
73
|
-
let count = 0;
|
|
74
|
-
|
|
75
|
-
let start: DOMHighResTimeStamp | undefined;
|
|
76
|
-
|
|
77
|
-
function step(timestamp: DOMHighResTimeStamp): void {
|
|
78
|
-
if (!timed.running) {
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
start ??= timestamp;
|
|
83
|
-
|
|
84
|
-
const elapsed = timestamp - start;
|
|
85
|
-
|
|
86
|
-
const elapsedMinimum = elapsed - milliseconds;
|
|
87
|
-
const elapsedMaximum = elapsed + milliseconds;
|
|
88
|
-
|
|
89
|
-
if (elapsedMinimum < timed.time && timed.time < elapsedMaximum) {
|
|
90
|
-
if (timed.running) {
|
|
91
|
-
timed.callback(timed.type === 'repeated' ? count : undefined);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
count += 1;
|
|
95
|
-
|
|
96
|
-
if (timed.type === 'repeated' && count < timed.count) {
|
|
97
|
-
start = undefined;
|
|
98
|
-
} else {
|
|
99
|
-
timed.stop();
|
|
100
|
-
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
timed.frame = window.requestAnimationFrame(step);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
timed.frame = window.requestAnimationFrame(step);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export class Repeated extends Timed<RepeatedCallback> {
|
|
113
|
-
constructor(callback: RepeatedCallback, time: number, count: number) {
|
|
114
|
-
super('repeated', callback, time, count);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export class Waited extends Timed<WaitedCallback> {
|
|
119
|
-
constructor(callback: WaitedCallback, time: number) {
|
|
120
|
-
super('waited', callback, time, 1);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export const Timer = {
|
|
125
|
-
repeat: (callback: RepeatedCallback, time: number, count: number): Repeated => {
|
|
126
|
-
return (new Repeated(callback, time, count)).start();
|
|
127
|
-
},
|
|
128
|
-
|
|
129
|
-
wait: (callback: WaitedCallback, time: number): Waited => {
|
|
130
|
-
return (new Waited(callback, time)).start();
|
|
131
|
-
},
|
|
132
|
-
}
|
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 {Repeated, Timer, Waited} from '../dist/timer.js';
|
|
2
|
-
|
|
3
|
-
describe('Timer, factory', function () {
|
|
4
|
-
it('should create and start a repeated timer', function () {
|
|
5
|
-
chai.assert.ok(Timer.repeat(() => {}, 0, 2) instanceof Repeated);
|
|
6
|
-
});
|
|
7
|
-
|
|
8
|
-
it('should create and start a waited timer', function () {
|
|
9
|
-
chai.assert.ok(Timer.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
|
-
Timer.repeat(() => {
|
|
32
|
-
value += 1;
|
|
33
|
-
}, 25, 10);
|
|
34
|
-
|
|
35
|
-
Timer.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 = Timer.repeat(() => {
|
|
46
|
-
value += 1;
|
|
47
|
-
}, 25, 10);
|
|
48
|
-
|
|
49
|
-
Timer.wait(() => {
|
|
50
|
-
repeated.stop();
|
|
51
|
-
}, 125);
|
|
52
|
-
|
|
53
|
-
Timer.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
|
-
Timer.wait(() => {
|
|
91
|
-
waited.stop();
|
|
92
|
-
}, 250);
|
|
93
|
-
|
|
94
|
-
Timer.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
|
-
Timer.wait(() => {
|
|
111
|
-
waited.restart();
|
|
112
|
-
}, 250);
|
|
113
|
-
|
|
114
|
-
Timer.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
|
-
}
|