ctrl-fx 0.0.1 → 0.1.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/dist/clipboard.d.ts +7 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +3 -0
- package/dist/db/effects.d.ts +78 -0
- package/dist/db/effects.d.ts.map +1 -0
- package/dist/db/effects.js +98 -0
- package/dist/db/errors.d.ts +21 -0
- package/dist/db/errors.d.ts.map +1 -0
- package/dist/db/errors.js +13 -0
- package/dist/db/index.d.ts +32 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +19 -0
- package/dist/db/keypath.d.ts +40 -0
- package/dist/db/keypath.d.ts.map +1 -0
- package/dist/db/keypath.js +20 -0
- package/dist/db/setup.d.ts +83 -0
- package/dist/db/setup.d.ts.map +1 -0
- package/dist/db/setup.js +100 -0
- package/dist/db/testdb.d.ts +19 -0
- package/dist/db/testdb.d.ts.map +1 -0
- package/dist/db/testdb.js +34 -0
- package/dist/dom/attrs.d.ts +67 -0
- package/dist/dom/attrs.d.ts.map +1 -0
- package/dist/dom/attrs.js +154 -0
- package/dist/dom/components.d.ts +43 -0
- package/dist/dom/components.d.ts.map +1 -0
- package/dist/dom/components.js +86 -0
- package/dist/dom/elems.d.ts +121 -0
- package/dist/dom/elems.d.ts.map +1 -0
- package/dist/dom/elems.js +52 -0
- package/dist/dom/events.d.ts +232 -0
- package/dist/dom/events.d.ts.map +1 -0
- package/dist/dom/events.js +289 -0
- package/dist/dom/index.d.ts +248 -0
- package/dist/dom/index.d.ts.map +1 -0
- package/dist/dom/index.js +266 -0
- package/dist/dom/nodeid.d.ts +9 -0
- package/dist/dom/nodeid.d.ts.map +1 -0
- package/dist/dom/nodeid.js +27 -0
- package/dist/dom/svg.d.ts +23 -0
- package/dist/dom/svg.d.ts.map +1 -0
- package/dist/dom/svg.js +1 -0
- package/dist/dom/views.d.ts +60 -0
- package/dist/dom/views.d.ts.map +1 -0
- package/dist/dom/views.js +154 -0
- package/dist/effects.d.ts +580 -0
- package/dist/effects.d.ts.map +1 -0
- package/dist/effects.js +1556 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +78 -0
- package/dist/internal/clipboard.d.ts +5 -0
- package/dist/internal/clipboard.d.ts.map +1 -0
- package/dist/internal/clipboard.js +33 -0
- package/dist/internal/cmpmgr.d.ts +46 -0
- package/dist/internal/cmpmgr.d.ts.map +1 -0
- package/dist/internal/cmpmgr.js +561 -0
- package/dist/internal/dbmgr.d.ts +11 -0
- package/dist/internal/dbmgr.d.ts.map +1 -0
- package/dist/internal/dbmgr.js +200 -0
- package/dist/internal/dominterpreter.d.ts +5 -0
- package/dist/internal/dominterpreter.d.ts.map +1 -0
- package/dist/internal/dominterpreter.js +337 -0
- package/dist/internal/eventmgr.d.ts +41 -0
- package/dist/internal/eventmgr.d.ts.map +1 -0
- package/dist/internal/eventmgr.js +696 -0
- package/dist/internal/index.d.ts +19 -0
- package/dist/internal/index.d.ts.map +1 -0
- package/dist/internal/index.js +38 -0
- package/dist/internal/interpreter.d.ts +10 -0
- package/dist/internal/interpreter.d.ts.map +1 -0
- package/dist/internal/interpreter.js +1 -0
- package/dist/internal/locutils.d.ts +4 -0
- package/dist/internal/locutils.d.ts.map +1 -0
- package/dist/internal/locutils.js +22 -0
- package/dist/internal/net.d.ts +4 -0
- package/dist/internal/net.d.ts.map +1 -0
- package/dist/internal/net.js +64 -0
- package/dist/internal/realdom.d.ts +249 -0
- package/dist/internal/realdom.d.ts.map +1 -0
- package/dist/internal/realdom.js +1 -0
- package/dist/internal/styleregistry.d.ts +6 -0
- package/dist/internal/styleregistry.d.ts.map +1 -0
- package/dist/internal/styleregistry.js +18 -0
- package/dist/internal/taskreg.d.ts +9 -0
- package/dist/internal/taskreg.d.ts.map +1 -0
- package/dist/internal/taskreg.js +28 -0
- package/dist/internal/testing.d.ts +12 -0
- package/dist/internal/testing.d.ts.map +1 -0
- package/dist/internal/testing.js +974 -0
- package/dist/internal/testinginterpreter.d.ts +10 -0
- package/dist/internal/testinginterpreter.d.ts.map +1 -0
- package/dist/internal/testinginterpreter.js +646 -0
- package/dist/internal/vdom.d.ts +93 -0
- package/dist/internal/vdom.d.ts.map +1 -0
- package/dist/internal/vdom.js +470 -0
- package/dist/json/index.d.ts +5 -0
- package/dist/json/index.d.ts.map +1 -0
- package/dist/json/index.js +2 -0
- package/dist/json/validation.d.ts +28 -0
- package/dist/json/validation.d.ts.map +1 -0
- package/dist/json/validation.js +8 -0
- package/dist/net/fragment.d.ts +10 -0
- package/dist/net/fragment.d.ts.map +1 -0
- package/dist/net/fragment.js +27 -0
- package/dist/net/index.d.ts +42 -0
- package/dist/net/index.d.ts.map +1 -0
- package/dist/net/index.js +60 -0
- package/dist/net/location.d.ts +21 -0
- package/dist/net/location.d.ts.map +1 -0
- package/dist/net/location.js +41 -0
- package/dist/net/path.d.ts +12 -0
- package/dist/net/path.d.ts.map +1 -0
- package/dist/net/path.js +29 -0
- package/dist/net/queryparam.d.ts +10 -0
- package/dist/net/queryparam.d.ts.map +1 -0
- package/dist/net/queryparam.js +34 -0
- package/dist/router.d.ts +40 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +77 -0
- package/dist/scroll.d.ts +7 -0
- package/dist/scroll.d.ts.map +1 -0
- package/dist/scroll.js +3 -0
- package/dist/testing.d.ts +248 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +159 -0
- package/dist/utils/apply.d.ts +9 -0
- package/dist/utils/apply.d.ts.map +1 -0
- package/dist/utils/apply.js +10 -0
- package/dist/utils/index.d.ts +22 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +138 -0
- package/dist/utils/lens.d.ts +18 -0
- package/dist/utils/lens.d.ts.map +1 -0
- package/dist/utils/lens.js +27 -0
- package/dist/utils/match.d.ts +17 -0
- package/dist/utils/match.d.ts.map +1 -0
- package/dist/utils/match.js +28 -0
- package/dist/utils/result.d.ts +47 -0
- package/dist/utils/result.d.ts.map +1 -0
- package/dist/utils/result.js +97 -0
- package/dist/webcomponent.d.ts +15 -0
- package/dist/webcomponent.d.ts.map +1 -0
- package/dist/webcomponent.js +43 -0
- package/package.json +1 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { dbVersion } from '../db';
|
|
2
|
+
import { constraintError, notFoundError, unexpectedError, } from '../db/errors';
|
|
3
|
+
import { run as runDbEffect } from '../db/effects';
|
|
4
|
+
import { run as runDbSetupEffect } from '../db/setup';
|
|
5
|
+
import { failure, success } from '../utils/result';
|
|
6
|
+
export class DbManager {
|
|
7
|
+
constructor() {
|
|
8
|
+
Object.defineProperty(this, "openDatabases", {
|
|
9
|
+
enumerable: true,
|
|
10
|
+
configurable: true,
|
|
11
|
+
writable: true,
|
|
12
|
+
value: new Map()
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
open(db, version, setup, callback) {
|
|
16
|
+
const idbFactory = globalThis.indexedDB;
|
|
17
|
+
if (!idbFactory) {
|
|
18
|
+
return callback(failure(unexpectedError({ message: 'IndexedDB not supported' })));
|
|
19
|
+
}
|
|
20
|
+
const openRequest = idbFactory.open(db, version);
|
|
21
|
+
openRequest.onblocked = _event => {
|
|
22
|
+
window.alert('A database upgrade is blocked. Please close other tabs with this app.');
|
|
23
|
+
};
|
|
24
|
+
let upgradeError = undefined;
|
|
25
|
+
openRequest.onupgradeneeded = versionChangeEvent => {
|
|
26
|
+
const idbDb = openRequest.result;
|
|
27
|
+
const tx = openRequest.transaction;
|
|
28
|
+
if (!tx) {
|
|
29
|
+
console.warn('Expected idb transaction to be non-null during upgrade');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const oldVersion = dbVersion(versionChangeEvent.oldVersion);
|
|
33
|
+
const effect = setup(oldVersion);
|
|
34
|
+
try {
|
|
35
|
+
runDbSetupEffect(effect, setupInterpreter(idbDb, tx), _result => { });
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
if (err instanceof Error)
|
|
39
|
+
upgradeError = err;
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
openRequest.onerror = event => {
|
|
44
|
+
if (upgradeError instanceof DOMException) {
|
|
45
|
+
if (upgradeError.name === 'ConstraintError') {
|
|
46
|
+
return callback(failure(constraintError(upgradeError)));
|
|
47
|
+
}
|
|
48
|
+
if (upgradeError.name === 'NotFoundError') {
|
|
49
|
+
return callback(failure(notFoundError(upgradeError)));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return callback(failure(unexpectedError({
|
|
53
|
+
message: extractMessage(event),
|
|
54
|
+
cause: upgradeError,
|
|
55
|
+
})));
|
|
56
|
+
};
|
|
57
|
+
openRequest.onsuccess = _event => {
|
|
58
|
+
this.openDatabases.set(db, openRequest.result);
|
|
59
|
+
callback(success(undefined));
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
runTransaction(db, objectStores, mode, effect, callback) {
|
|
63
|
+
const idbDb = this.openDatabases.get(db);
|
|
64
|
+
if (!idbDb) {
|
|
65
|
+
return callback(failure(unexpectedError({ message: `Database '${db}' is not open` })));
|
|
66
|
+
}
|
|
67
|
+
const tx = idbDb.transaction([...objectStores], mode);
|
|
68
|
+
let txError = null;
|
|
69
|
+
tx.onerror = _event => {
|
|
70
|
+
txError = tx.error;
|
|
71
|
+
};
|
|
72
|
+
tx.onabort = _event => {
|
|
73
|
+
if (txError !== null) {
|
|
74
|
+
if (txError.name === 'ConstraintError') {
|
|
75
|
+
return callback(failure(constraintError(txError)));
|
|
76
|
+
}
|
|
77
|
+
if (txError.name === 'NotFoundError') {
|
|
78
|
+
return callback(failure(notFoundError(txError)));
|
|
79
|
+
}
|
|
80
|
+
return callback(failure(unexpectedError({ cause: txError })));
|
|
81
|
+
}
|
|
82
|
+
return callback(failure(unexpectedError({ message: 'Transaction aborted' })));
|
|
83
|
+
};
|
|
84
|
+
tx.oncomplete = _event => {
|
|
85
|
+
callback(success(undefined));
|
|
86
|
+
};
|
|
87
|
+
runDbEffect(effect, dbInterpreter(tx), _result => { });
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function setupInterpreter(db, tx) {
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
+
return (op, onComplete) => {
|
|
93
|
+
switch (op._type) {
|
|
94
|
+
case 'CreateObjectStore': {
|
|
95
|
+
db.createObjectStore(op.objectStore, objectStoreKeyOptions(op.keyPath));
|
|
96
|
+
onComplete(undefined);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
case 'CreateIndex': {
|
|
100
|
+
const store = tx.objectStore(op.objectStore);
|
|
101
|
+
store.createIndex(op.index, indexKeyPathValue(op.keyPath), {
|
|
102
|
+
unique: op.unique,
|
|
103
|
+
});
|
|
104
|
+
onComplete(undefined);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
case 'DeleteObjectStore': {
|
|
108
|
+
db.deleteObjectStore(op.objectStore);
|
|
109
|
+
onComplete(undefined);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
case 'DeleteIndex': {
|
|
113
|
+
const store = tx.objectStore(op.objectStore);
|
|
114
|
+
store.deleteIndex(op.index);
|
|
115
|
+
onComplete(undefined);
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
case 'GetObjectStoreNames': {
|
|
119
|
+
onComplete(Array.from(db.objectStoreNames));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
case 'GetIndexNames': {
|
|
123
|
+
const store = tx.objectStore(op.objectStore);
|
|
124
|
+
onComplete(Array.from(store.indexNames));
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
case 'RunDbEffect': {
|
|
128
|
+
runDbEffect(op.effect, dbInterpreter(tx), _result => onComplete(undefined));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function dbInterpreter(tx) {
|
|
135
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
136
|
+
return (op, onComplete) => {
|
|
137
|
+
switch (op._type) {
|
|
138
|
+
case 'Add': {
|
|
139
|
+
const req = tx.objectStore(op.objectStore).add(op.value);
|
|
140
|
+
req.onsuccess = () => onComplete(undefined);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
case 'Put': {
|
|
144
|
+
const req = tx.objectStore(op.objectStore).put(op.value);
|
|
145
|
+
req.onsuccess = () => onComplete(undefined);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
case 'Get': {
|
|
149
|
+
const req = tx.objectStore(op.objectStore).get(op.key);
|
|
150
|
+
req.onsuccess = () => onComplete(req.result ?? undefined);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
case 'GetAll': {
|
|
154
|
+
const req = tx.objectStore(op.objectStore).getAll();
|
|
155
|
+
req.onsuccess = () => onComplete(req.result);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
case 'Delete': {
|
|
159
|
+
const req = tx.objectStore(op.objectStore).delete(op.key);
|
|
160
|
+
req.onsuccess = () => onComplete(undefined);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
case 'Count': {
|
|
164
|
+
const req = tx.objectStore(op.objectStore).count();
|
|
165
|
+
req.onsuccess = () => onComplete(req.result);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
function objectStoreKeyOptions(keyPath) {
|
|
172
|
+
switch (keyPath._type) {
|
|
173
|
+
case 'AutoIncrement':
|
|
174
|
+
return { keyPath: keyPath.value, autoIncrement: true };
|
|
175
|
+
case 'Manual':
|
|
176
|
+
return { keyPath: keyPath.value, autoIncrement: false };
|
|
177
|
+
case 'Multi':
|
|
178
|
+
return {
|
|
179
|
+
keyPath: [keyPath.first, keyPath.second, ...keyPath.rest],
|
|
180
|
+
autoIncrement: false,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function indexKeyPathValue(keyPath) {
|
|
185
|
+
switch (keyPath._type) {
|
|
186
|
+
case 'SingleIndex':
|
|
187
|
+
return keyPath.value;
|
|
188
|
+
case 'MultiIndex':
|
|
189
|
+
return [keyPath.first, keyPath.second, ...keyPath.rest];
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
function extractMessage(event) {
|
|
193
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
194
|
+
const m = event.message;
|
|
195
|
+
if (typeof m === 'string')
|
|
196
|
+
return m;
|
|
197
|
+
if (m != null)
|
|
198
|
+
return `${m}`;
|
|
199
|
+
return undefined;
|
|
200
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Effect } from '../effects';
|
|
2
|
+
import type { Callbacks } from './interpreter';
|
|
3
|
+
import { TaskRegistry } from './taskreg';
|
|
4
|
+
export declare function domInterpreter<State, Event, A>(effect: Effect<State, Event, A>, callbacks: Callbacks<State, Event, A>, taskRegistry: TaskRegistry): void;
|
|
5
|
+
//# sourceMappingURL=dominterpreter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dominterpreter.d.ts","sourceRoot":"","sources":["../../src/internal/dominterpreter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAU,KAAK,MAAM,EAAe,MAAM,YAAY,CAAA;AAK7D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAI9C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAIxC,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,EAC5C,MAAM,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,EAC/B,SAAS,EAAE,SAAS,CAAC,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,EACrC,YAAY,EAAE,YAAY,GACzB,IAAI,CAobN"}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
import { generateUuid } from '.';
|
|
2
|
+
import { permission } from '..';
|
|
3
|
+
import { taskId } from '../effects';
|
|
4
|
+
import { formatLocation, parseInternalLocation } from '../net/location';
|
|
5
|
+
import { scrollElementError } from '../scroll';
|
|
6
|
+
import { failure, success } from '../utils/result';
|
|
7
|
+
import { exhaustivenessCheck } from '../utils';
|
|
8
|
+
import { readClipboard, writeClipboard } from './clipboard';
|
|
9
|
+
import { DbManager } from './dbmgr';
|
|
10
|
+
import { makeHttpRequest } from './net';
|
|
11
|
+
import { TaskRegistry } from './taskreg';
|
|
12
|
+
const dbManager = new DbManager();
|
|
13
|
+
export function domInterpreter(effect, callbacks, taskRegistry) {
|
|
14
|
+
switch (effect._type) {
|
|
15
|
+
case 'Return': {
|
|
16
|
+
callbacks.onComplete(effect.value);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
case 'FlatMap': {
|
|
20
|
+
domInterpreter(effect.effect, {
|
|
21
|
+
...callbacks,
|
|
22
|
+
onComplete(result) {
|
|
23
|
+
domInterpreter(effect.next(result), callbacks, taskRegistry);
|
|
24
|
+
},
|
|
25
|
+
}, taskRegistry);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
case 'Suspend': {
|
|
29
|
+
switch (effect.operation._type) {
|
|
30
|
+
case 'Alert': {
|
|
31
|
+
globalThis.window.alert(effect.operation.input);
|
|
32
|
+
callbacks.onComplete(undefined);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
case 'Confirm': {
|
|
36
|
+
callbacks.onComplete(globalThis.window.confirm(effect.operation.input));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
case 'Prompt': {
|
|
40
|
+
callbacks.onComplete(globalThis.window.prompt(effect.operation.input.message, effect.operation.input.default));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
case 'GetNotificationPermission': {
|
|
44
|
+
callbacks.onComplete(permission(globalThis.Notification.permission));
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
case 'RequestNotificationPermission': {
|
|
48
|
+
globalThis.Notification.requestPermission().then(perm => {
|
|
49
|
+
callbacks.onComplete(permission(perm));
|
|
50
|
+
});
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
case 'GetLocation': {
|
|
54
|
+
const loc = globalThis.window.location;
|
|
55
|
+
callbacks.onComplete(parseInternalLocation(loc.pathname + loc.search + loc.hash));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
case 'Async': {
|
|
59
|
+
const { effect: innerEffect, delayInMillis } = effect.operation.input;
|
|
60
|
+
setTimeout(() => {
|
|
61
|
+
domInterpreter(innerEffect, { ...callbacks, onComplete() { } }, taskRegistry);
|
|
62
|
+
}, delayInMillis);
|
|
63
|
+
callbacks.onComplete(undefined);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
case 'CancelTask': {
|
|
67
|
+
taskRegistry.cancel(effect.operation.input);
|
|
68
|
+
callbacks.onComplete(undefined);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
case 'ClearAppBadge': {
|
|
72
|
+
if (globalThis.navigator.clearAppBadge) {
|
|
73
|
+
globalThis.navigator.clearAppBadge();
|
|
74
|
+
}
|
|
75
|
+
callbacks.onComplete(undefined);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
case 'SetAppBadge': {
|
|
79
|
+
if (globalThis.navigator.setAppBadge) {
|
|
80
|
+
globalThis.navigator.setAppBadge(effect.operation.input);
|
|
81
|
+
}
|
|
82
|
+
callbacks.onComplete(undefined);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
case 'SetDocumentTitle': {
|
|
86
|
+
globalThis.document.title = effect.operation.input;
|
|
87
|
+
callbacks.onComplete(undefined);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
case 'FireEvent': {
|
|
91
|
+
callbacks.onFireEvent(effect.operation.input);
|
|
92
|
+
callbacks.onComplete(undefined);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
case 'GetState': {
|
|
96
|
+
callbacks.onComplete(callbacks.getState());
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
case 'GetTime': {
|
|
100
|
+
callbacks.onComplete(new Date());
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
case 'GetRandom': {
|
|
104
|
+
callbacks.onComplete(Math.random());
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
case 'MakeHttpRequest': {
|
|
108
|
+
makeHttpRequest(effect.operation.input, result => callbacks.onComplete(result));
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
case 'Log': {
|
|
112
|
+
console.log(effect.operation.input);
|
|
113
|
+
callbacks.onComplete(undefined);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
case 'Product': {
|
|
117
|
+
let resultA = '__ctrl_fx_unset_result';
|
|
118
|
+
let resultB = '__ctrl_fx_unset_result';
|
|
119
|
+
domInterpreter(effect.operation.input[0], {
|
|
120
|
+
...callbacks,
|
|
121
|
+
onComplete(a) {
|
|
122
|
+
resultA = a;
|
|
123
|
+
if (resultB !== '__ctrl_fx_unset_result') {
|
|
124
|
+
callbacks.onComplete([resultA, resultB]);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
}, taskRegistry);
|
|
128
|
+
domInterpreter(effect.operation.input[1], {
|
|
129
|
+
...callbacks,
|
|
130
|
+
onComplete(b) {
|
|
131
|
+
resultB = b;
|
|
132
|
+
if (resultA !== '__ctrl_fx_unset_result') {
|
|
133
|
+
callbacks.onComplete([resultA, resultB]);
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
}, taskRegistry);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
case 'ScheduleTask': {
|
|
140
|
+
let tskId;
|
|
141
|
+
// clear task if its already scheduled
|
|
142
|
+
if (effect.operation.input.taskId) {
|
|
143
|
+
taskRegistry.cancel(effect.operation.input.taskId);
|
|
144
|
+
tskId = effect.operation.input.taskId;
|
|
145
|
+
}
|
|
146
|
+
// setTimeout (one-shot)
|
|
147
|
+
if (effect.operation.input.repeatIntervalInMillis === undefined) {
|
|
148
|
+
const timerId = globalThis.setTimeout(() => {
|
|
149
|
+
domInterpreter(effect.operation.input.task, { ...callbacks, onComplete() { } }, taskRegistry);
|
|
150
|
+
}, effect.operation.input.initialDelayInMillis);
|
|
151
|
+
tskId ||= taskId(generateUuid());
|
|
152
|
+
taskRegistry.set(tskId, () => clearTimeout(timerId));
|
|
153
|
+
// setInterval (delay == interval shortcut)
|
|
154
|
+
}
|
|
155
|
+
else if (effect.operation.input.initialDelayInMillis ===
|
|
156
|
+
effect.operation.input.repeatIntervalInMillis) {
|
|
157
|
+
const timerId = globalThis.setInterval(() => {
|
|
158
|
+
domInterpreter(effect.operation.input.task, { ...callbacks, onComplete() { } }, taskRegistry);
|
|
159
|
+
}, effect.operation.input.repeatIntervalInMillis);
|
|
160
|
+
tskId ||= taskId(generateUuid());
|
|
161
|
+
taskRegistry.set(tskId, () => clearInterval(timerId));
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
// initial delay differs from repeat interval: setTimeout then setInterval
|
|
165
|
+
tskId ||= taskId(generateUuid());
|
|
166
|
+
const timerId = globalThis.setTimeout(() => {
|
|
167
|
+
domInterpreter(effect.operation.input.task, {
|
|
168
|
+
...callbacks,
|
|
169
|
+
onComplete() {
|
|
170
|
+
const newTimerId = globalThis.setInterval(() => {
|
|
171
|
+
domInterpreter(effect.operation.input.task, { ...callbacks, onComplete() { } }, taskRegistry);
|
|
172
|
+
}, effect.operation.input.repeatIntervalInMillis);
|
|
173
|
+
taskRegistry.set(tskId, () => clearInterval(newTimerId));
|
|
174
|
+
},
|
|
175
|
+
}, taskRegistry);
|
|
176
|
+
}, effect.operation.input.initialDelayInMillis);
|
|
177
|
+
taskRegistry.set(tskId, () => clearTimeout(timerId));
|
|
178
|
+
}
|
|
179
|
+
callbacks.onComplete(tskId);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
case 'SetTimeout': {
|
|
183
|
+
setTimeout(() => {
|
|
184
|
+
callbacks.onComplete(undefined);
|
|
185
|
+
}, effect.operation.input);
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
case 'PushState': {
|
|
189
|
+
const url = formatLocation(effect.operation.input);
|
|
190
|
+
history.pushState(null, '', url);
|
|
191
|
+
window.dispatchEvent(new Event('locationchange'));
|
|
192
|
+
callbacks.onComplete(undefined);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
case 'ReplaceState': {
|
|
196
|
+
const url = formatLocation(effect.operation.input);
|
|
197
|
+
history.replaceState(null, '', url);
|
|
198
|
+
window.dispatchEvent(new Event('locationchange'));
|
|
199
|
+
callbacks.onComplete(undefined);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
case 'Go': {
|
|
203
|
+
history.go(effect.operation.input);
|
|
204
|
+
callbacks.onComplete(undefined);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
case 'GetStorageItem': {
|
|
208
|
+
const store = effect.operation.input.storage === 'local'
|
|
209
|
+
? localStorage
|
|
210
|
+
: sessionStorage;
|
|
211
|
+
callbacks.onComplete(store.getItem(effect.operation.input.key));
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
case 'SetStorageItem': {
|
|
215
|
+
const store = effect.operation.input.storage === 'local'
|
|
216
|
+
? localStorage
|
|
217
|
+
: sessionStorage;
|
|
218
|
+
store.setItem(effect.operation.input.key, effect.operation.input.value);
|
|
219
|
+
callbacks.onComplete(undefined);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
case 'RemoveStorageItem': {
|
|
223
|
+
const store = effect.operation.input.storage === 'local'
|
|
224
|
+
? localStorage
|
|
225
|
+
: sessionStorage;
|
|
226
|
+
store.removeItem(effect.operation.input.key);
|
|
227
|
+
callbacks.onComplete(undefined);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
case 'ClearStorage': {
|
|
231
|
+
const store = effect.operation.input.storage === 'local'
|
|
232
|
+
? localStorage
|
|
233
|
+
: sessionStorage;
|
|
234
|
+
store.clear();
|
|
235
|
+
callbacks.onComplete(undefined);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
case 'OpenDatabase': {
|
|
239
|
+
const { db, version, setup } = effect.operation.input;
|
|
240
|
+
dbManager.open(db, version, setup, result => {
|
|
241
|
+
callbacks.onComplete(result);
|
|
242
|
+
});
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
case 'RunDbTransaction': {
|
|
246
|
+
const { db, objectStores, mode, effect: dbEffect, } = effect.operation.input;
|
|
247
|
+
dbManager.runTransaction(db, objectStores, mode, dbEffect, result => {
|
|
248
|
+
callbacks.onComplete(result);
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
case 'UpdateState': {
|
|
253
|
+
callbacks.setState(effect.operation.input(callbacks.getState()));
|
|
254
|
+
callbacks.onComplete(undefined);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
case 'GenerateUuid': {
|
|
258
|
+
callbacks.onComplete(generateUuid());
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
case 'ReadClipboard': {
|
|
262
|
+
readClipboard(result => callbacks.onComplete(result));
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
case 'WriteClipboard': {
|
|
266
|
+
writeClipboard(effect.operation.input, result => callbacks.onComplete(result));
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
case 'Download': {
|
|
270
|
+
const { filename, content, contentType } = effect.operation.input;
|
|
271
|
+
const blob = new Blob([content], { type: contentType });
|
|
272
|
+
const url = URL.createObjectURL(blob);
|
|
273
|
+
const a = globalThis.document.createElement('a');
|
|
274
|
+
a.href = url;
|
|
275
|
+
a.download = filename;
|
|
276
|
+
globalThis.document.body.appendChild(a);
|
|
277
|
+
a.click();
|
|
278
|
+
globalThis.document.body.removeChild(a);
|
|
279
|
+
URL.revokeObjectURL(url);
|
|
280
|
+
callbacks.onComplete(undefined);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
case 'PostBroadcastMessage': {
|
|
284
|
+
const bc = new BroadcastChannel(effect.operation.input.channel);
|
|
285
|
+
bc.postMessage(effect.operation.input.message);
|
|
286
|
+
bc.close();
|
|
287
|
+
callbacks.onComplete(undefined);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
case 'SubscribeToBroadcastChannel': {
|
|
291
|
+
const { channel, handler, taskId: tskIdInput } = effect.operation.input;
|
|
292
|
+
const tskId = tskIdInput ?? taskId(generateUuid());
|
|
293
|
+
const bc = new BroadcastChannel(channel);
|
|
294
|
+
bc.onmessage = (event) => {
|
|
295
|
+
domInterpreter(handler(event.data), { ...callbacks, onComplete() { } }, taskRegistry);
|
|
296
|
+
};
|
|
297
|
+
taskRegistry.set(tskId, () => bc.close());
|
|
298
|
+
callbacks.onComplete(tskId);
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
case 'ScrollWindow': {
|
|
302
|
+
globalThis.window.scrollTo(effect.operation.input);
|
|
303
|
+
callbacks.onComplete(undefined);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
case 'ScrollElement': {
|
|
307
|
+
const { selector, options } = effect.operation.input;
|
|
308
|
+
const el = globalThis.document.querySelector(selector);
|
|
309
|
+
if (el === null) {
|
|
310
|
+
callbacks.onComplete(failure(scrollElementError(selector)));
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
el.scrollTo(options);
|
|
314
|
+
callbacks.onComplete(success(undefined));
|
|
315
|
+
}
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
case 'CustomEffect': {
|
|
319
|
+
const { args, f } = effect.operation.input;
|
|
320
|
+
const result = f(args);
|
|
321
|
+
if (result instanceof Promise) {
|
|
322
|
+
result.then(out => callbacks.onComplete(out));
|
|
323
|
+
}
|
|
324
|
+
else {
|
|
325
|
+
callbacks.onComplete(result);
|
|
326
|
+
}
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
default:
|
|
330
|
+
exhaustivenessCheck(effect.operation);
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
}
|
|
334
|
+
default:
|
|
335
|
+
exhaustivenessCheck(effect);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type EventListenerResult, type EventOptions } from '../dom/events';
|
|
2
|
+
import type { Effect } from '../effects';
|
|
3
|
+
import type { RealWindow } from './realdom';
|
|
4
|
+
import type { ComponentNode, InternalElementNode, ViewNode } from './vdom';
|
|
5
|
+
type ListenerTotals = {
|
|
6
|
+
regular: number;
|
|
7
|
+
capture: number;
|
|
8
|
+
};
|
|
9
|
+
type ListenerCounts<EventType extends string> = Record<EventType, ListenerTotals>;
|
|
10
|
+
export declare function makeListenerCounts<EventTypes extends readonly string[]>(eventTypes: EventTypes): ListenerCounts<(typeof eventTypes)[number]>;
|
|
11
|
+
/** Given current counts of all listeners, adjust them for a specific node given
|
|
12
|
+
* its old listeners and its new listeners. Return which listener counts have
|
|
13
|
+
* dropped to zero and which listener counts have gone from zero to a positive
|
|
14
|
+
* number. Also include a set of all the new event types.
|
|
15
|
+
*/
|
|
16
|
+
export declare function adjustCountsAndGetListenerTypesToRemoveAndAdd<K extends string, L extends {
|
|
17
|
+
_type: K;
|
|
18
|
+
options?: EventOptions;
|
|
19
|
+
}>(counts: Record<K, ListenerTotals>, oldListeners: readonly L[], newListeners: readonly L[]): {
|
|
20
|
+
toRemove: Map<K, {
|
|
21
|
+
regular: boolean;
|
|
22
|
+
capture: boolean;
|
|
23
|
+
}>;
|
|
24
|
+
toAdd: Map<K, {
|
|
25
|
+
regular: boolean;
|
|
26
|
+
capture: boolean;
|
|
27
|
+
}>;
|
|
28
|
+
allNewEvents: Map<K, {
|
|
29
|
+
regular: boolean;
|
|
30
|
+
capture: boolean;
|
|
31
|
+
}>;
|
|
32
|
+
};
|
|
33
|
+
export declare class EventManager {
|
|
34
|
+
private containerDelegate;
|
|
35
|
+
private elementDelegate;
|
|
36
|
+
constructor(window: RealWindow, runEffect: (effect: Effect<unknown, unknown, EventListenerResult>, node: InternalElementNode | ComponentNode | ViewNode, onResult: (result: EventListenerResult) => void) => void);
|
|
37
|
+
setContainerListeners(node: ComponentNode | ViewNode): void;
|
|
38
|
+
setElementListeners(node: InternalElementNode): void;
|
|
39
|
+
}
|
|
40
|
+
export {};
|
|
41
|
+
//# sourceMappingURL=eventmgr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eventmgr.d.ts","sourceRoot":"","sources":["../../src/internal/eventmgr.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAMlB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAIxC,OAAO,KAAK,EAMV,UAAU,EACX,MAAM,WAAW,CAAA;AAClB,OAAO,KAAK,EAAE,aAAa,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAoB1E,KAAK,cAAc,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAE1D,KAAK,cAAc,CAAC,SAAS,SAAS,MAAM,IAAI,MAAM,CACpD,SAAS,EACT,cAAc,CACf,CAAA;AAED,wBAAgB,kBAAkB,CAAC,UAAU,SAAS,SAAS,MAAM,EAAE,EACrE,UAAU,EAAE,UAAU,GACrB,cAAc,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC,CAK7C;AA2BD;;;;GAIG;AACH,wBAAgB,6CAA6C,CAC3D,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS;IAAE,KAAK,EAAE,CAAC,CAAC;IAAC,OAAO,CAAC,EAAE,YAAY,CAAA;CAAE,EAE9C,MAAM,EAAE,MAAM,CAAC,CAAC,EAAE,cAAc,CAAC,EACjC,YAAY,EAAE,SAAS,CAAC,EAAE,EAC1B,YAAY,EAAE,SAAS,CAAC,EAAE,GACzB;IACD,QAAQ,EAAE,GAAG,CAAC,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACxD,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;IACrD,YAAY,EAAE,GAAG,CAAC,CAAC,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAA;CAC7D,CA8FA;AA8pBD,qBAAa,YAAY;IACvB,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,eAAe,CAA6B;gBAGlD,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,CACT,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,mBAAmB,CAAC,EACrD,IAAI,EAAE,mBAAmB,GAAG,aAAa,GAAG,QAAQ,EACpD,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,KAC5C,IAAI;IASX,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,QAAQ,GAAG,IAAI;IAI3D,mBAAmB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI;CAGrD"}
|