@m2c2kit/cli 0.1.9 → 0.1.12
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/.env +1 -1
- package/dist/cli.js +4 -0
- package/dist/scripts/post-install.mjs +27 -0
- package/dist/templates/index.html.handlebars +1 -1
- package/dist/templates/package.json.handlebars +7 -6
- package/dist/templates/rollup.config.js.handlebars +5 -1
- package/dist/templates/starter.ts.handlebars +106 -142
- package/dist/templates/tsconfig.json.handlebars +2 -1
- package/package.json +7 -7
package/dist/.env
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
CLI_VERSION=0.1.
|
|
1
|
+
CLI_VERSION=0.1.12
|
package/dist/cli.js
CHANGED
|
@@ -146,6 +146,10 @@ await yarg
|
|
|
146
146
|
sourceFilePath: path.join(packageHomeFolderPath, "fonts", "roboto", "Roboto-Regular.ttf"),
|
|
147
147
|
destinationFilePath: path.join(newFolderPath, "fonts", "roboto", "Roboto-Regular.ttf"),
|
|
148
148
|
},
|
|
149
|
+
{
|
|
150
|
+
sourceFilePath: path.join(packageHomeFolderPath, "scripts", "post-install.mjs"),
|
|
151
|
+
destinationFilePath: path.join(newFolderPath, "post-install.mjs"),
|
|
152
|
+
},
|
|
149
153
|
];
|
|
150
154
|
let errorCopyingFiles = false;
|
|
151
155
|
copyFiles.forEach((c) => {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
import { resolve, basename } from "path";
|
|
4
|
+
|
|
5
|
+
const { dependencies } = JSON.parse(fs.readFileSync("./package.json"));
|
|
6
|
+
|
|
7
|
+
/** If this m2c2kit app uses surveys, then copy the required css
|
|
8
|
+
* files from node_modules so they can be bundled */
|
|
9
|
+
if (Object.keys(dependencies).includes("@m2c2kit/survey")) {
|
|
10
|
+
// does ./css folder exist? if not, create
|
|
11
|
+
if (!fs.existsSync("./css")) {
|
|
12
|
+
fs.mkdirSync("./css");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const cssDistDir = "./node_modules/@m2c2kit/survey/dist/css/";
|
|
16
|
+
const cssFiles = fs
|
|
17
|
+
.readdirSync(cssDistDir, {
|
|
18
|
+
withFileTypes: true,
|
|
19
|
+
})
|
|
20
|
+
.filter((dirent) => !dirent.isDirectory())
|
|
21
|
+
.map((dirent) => resolve(cssDistDir, dirent.name));
|
|
22
|
+
|
|
23
|
+
cssFiles.forEach((file) => {
|
|
24
|
+
const sourceContents = fs.readFileSync(file);
|
|
25
|
+
fs.writeFileSync(`./css/${basename(file)}`, sourceContents);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
height: 100vh;
|
|
21
21
|
width: 100vw;
|
|
22
22
|
">
|
|
23
|
-
<canvas style="height: 100vh; width: 100vw"></canvas>
|
|
23
|
+
<canvas style="height: 100vh; width: 100vw" id="m2c2-canvas"></canvas>
|
|
24
24
|
<!-- If you don't want the game to start immediately, remove session.start()
|
|
25
25
|
from the code and call session.start() somehow else, such as with
|
|
26
26
|
the button shown below or a programmatic call -->
|
|
@@ -3,18 +3,19 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"serve": "rollup -c --watch --configServe",
|
|
6
|
-
"build": "rollup -c --configProd"
|
|
6
|
+
"build": "rollup -c --configProd",
|
|
7
|
+
"postinstall": "node ./post-install.mjs"
|
|
7
8
|
},
|
|
8
9
|
"private": true,
|
|
9
10
|
"dependencies": {
|
|
10
|
-
"@m2c2kit/core": "0.1.
|
|
11
|
-
"@m2c2kit/addons": "0.1.
|
|
11
|
+
"@m2c2kit/core": "0.1.10",
|
|
12
|
+
"@m2c2kit/addons": "0.1.10"
|
|
12
13
|
},
|
|
13
14
|
"devDependencies": {
|
|
14
|
-
"rollup": "2.
|
|
15
|
-
"@rollup/plugin-typescript": "8.3.
|
|
15
|
+
"rollup": "2.70.0",
|
|
16
|
+
"@rollup/plugin-typescript": "8.3.1",
|
|
16
17
|
"@rollup/plugin-node-resolve": "13.1.3",
|
|
17
|
-
"@rollup/plugin-commonjs": "21.0.
|
|
18
|
+
"@rollup/plugin-commonjs": "21.0.2",
|
|
18
19
|
"rollup-plugin-shim": "1.0.0",
|
|
19
20
|
"rollup-plugin-copy": "3.4.0",
|
|
20
21
|
"rollup-plugin-delete": "2.0.0",
|
|
@@ -1,29 +1,30 @@
|
|
|
1
1
|
import {
|
|
2
|
-
WebColors,
|
|
3
|
-
Action,
|
|
4
2
|
Game,
|
|
3
|
+
Action,
|
|
5
4
|
Scene,
|
|
6
|
-
|
|
7
|
-
Point,
|
|
5
|
+
Shape,
|
|
8
6
|
Label,
|
|
7
|
+
WebColors,
|
|
9
8
|
LabelHorizontalAlignmentMode,
|
|
10
|
-
Shape,
|
|
11
|
-
Rect,
|
|
12
|
-
GameOptions,
|
|
13
9
|
GameParameters,
|
|
10
|
+
GameOptions,
|
|
14
11
|
TrialSchema,
|
|
15
12
|
Session,
|
|
16
|
-
GameTrialEvent,
|
|
17
|
-
GameLifecycleEvent,
|
|
18
13
|
SessionLifecycleEvent,
|
|
19
|
-
|
|
20
|
-
|
|
14
|
+
ActivityDataEvent,
|
|
15
|
+
ActivityLifecycleEvent,
|
|
16
|
+
Sprite,
|
|
17
|
+
Timer,
|
|
21
18
|
} from "@m2c2kit/core";
|
|
22
19
|
import { Button, Instructions } from "@m2c2kit/addons";
|
|
23
20
|
|
|
24
21
|
class {{className}} extends Game {
|
|
25
22
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
23
|
constructor() {
|
|
24
|
+
/**
|
|
25
|
+
* These are configurable game parameters and their defaults.
|
|
26
|
+
* At run time, they can be changed with the setParameters() method.
|
|
27
|
+
*/
|
|
27
28
|
const defaultParameters: GameParameters = {
|
|
28
29
|
ReadyTime: {
|
|
29
30
|
value: 1000,
|
|
@@ -33,9 +34,16 @@ class {{className}} extends Game {
|
|
|
33
34
|
TrialNum: { value: 3, description: "How many trials to run" },
|
|
34
35
|
};
|
|
35
36
|
|
|
37
|
+
/**
|
|
38
|
+
* This describes all the data that will be generated by the assessment.
|
|
39
|
+
* At runtime, when a trial completes, the data will be returned to the
|
|
40
|
+
* session with a callback, along with this schema transformed into
|
|
41
|
+
* JSON Schema Draft-07 format.
|
|
42
|
+
*/
|
|
36
43
|
const demoTrialSchema: TrialSchema = {
|
|
37
44
|
colorChosen: { type: "string", description: "the color that was picked" },
|
|
38
45
|
correct: { type: "boolean", description: "was the answer correct?" },
|
|
46
|
+
responseTime: { type: "number", description: "response time (ms) to choose shape" }
|
|
39
47
|
};
|
|
40
48
|
|
|
41
49
|
const options: GameOptions = {
|
|
@@ -44,12 +52,12 @@ class {{className}} extends Game {
|
|
|
44
52
|
uri: "https://your-repo-or-webpage-here",
|
|
45
53
|
shortDescription: "A brief couple sentence description.",
|
|
46
54
|
longDescription: "An extended, many-sentence description.",
|
|
47
|
-
showFps:
|
|
55
|
+
showFps: false,
|
|
48
56
|
trialSchema: demoTrialSchema,
|
|
49
57
|
parameters: defaultParameters,
|
|
50
|
-
// set this color so we can see the boundaries of the game during development,
|
|
51
|
-
// but typically we would not set this
|
|
52
|
-
bodyBackgroundColor: WebColors.Wheat,
|
|
58
|
+
// You can set this color so we can see the boundaries of the game during development,
|
|
59
|
+
// but typically we would not set this, so it is commented out
|
|
60
|
+
// bodyBackgroundColor: WebColors.Wheat,
|
|
53
61
|
// note: using 2:1 aspect ratio, because that is closer to modern phones
|
|
54
62
|
width: 400,
|
|
55
63
|
height: 800,
|
|
@@ -80,6 +88,9 @@ class {{className}} extends Game {
|
|
|
80
88
|
};
|
|
81
89
|
|
|
82
90
|
super(options);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
init(): void {
|
|
83
94
|
// just for convenience, alias the variable game to "this"
|
|
84
95
|
// (even though eslint doesn't like it)
|
|
85
96
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
@@ -97,6 +108,7 @@ class {{className}} extends Game {
|
|
|
97
108
|
textFontSize: 24,
|
|
98
109
|
titleFontSize: 30,
|
|
99
110
|
image: "smiley",
|
|
111
|
+
imageMarginBottom: 24
|
|
100
112
|
},
|
|
101
113
|
{
|
|
102
114
|
title: "{{appName}} Demo",
|
|
@@ -125,19 +137,19 @@ class {{className}} extends Game {
|
|
|
125
137
|
const getReadyMessage = new Label({
|
|
126
138
|
text: "Get Ready",
|
|
127
139
|
fontSize: 24,
|
|
128
|
-
position:
|
|
140
|
+
position: { x: 200, y: 400 },
|
|
129
141
|
});
|
|
130
142
|
getReadyScene.addChild(getReadyMessage);
|
|
131
143
|
|
|
132
144
|
// example of how to use an image. The image must be previously loaded
|
|
133
145
|
const starSprite = new Sprite({
|
|
134
146
|
imageName: "star",
|
|
135
|
-
position:
|
|
147
|
+
position: { x: 200, y: 500 },
|
|
136
148
|
});
|
|
137
149
|
getReadyScene.addChild(starSprite);
|
|
138
150
|
|
|
139
|
-
// getReadyScene.
|
|
140
|
-
getReadyScene.
|
|
151
|
+
// getReadyScene.onSetup() has a callback that is executed each time this scene is shown
|
|
152
|
+
getReadyScene.onSetup(() => {
|
|
141
153
|
getReadyScene.run(
|
|
142
154
|
Action.Sequence([
|
|
143
155
|
// Get the wait duration from the default game parameters, defined above
|
|
@@ -151,32 +163,32 @@ class {{className}} extends Game {
|
|
|
151
163
|
);
|
|
152
164
|
});
|
|
153
165
|
|
|
154
|
-
// these entities before the
|
|
166
|
+
// these entities before the onSetup() can be defined outside of a onSetup()
|
|
155
167
|
// because they exist through multiple trials
|
|
156
168
|
// Their position and how they respond to interactions may differ across trials,
|
|
157
|
-
// and that logic will be written within a
|
|
169
|
+
// and that logic will be written within a onSetup()
|
|
158
170
|
const chooseRectangleScene = new Scene({
|
|
159
171
|
backgroundColor: WebColors.LightGray,
|
|
160
172
|
});
|
|
161
173
|
game.addScene(chooseRectangleScene);
|
|
162
174
|
const redRect = new Shape({
|
|
163
|
-
rect:
|
|
175
|
+
rect: { width: 150, height: 100 },
|
|
164
176
|
fillColor: WebColors.Red,
|
|
165
177
|
});
|
|
166
178
|
chooseRectangleScene.addChild(redRect);
|
|
167
179
|
const blueRect = new Shape({
|
|
168
|
-
rect:
|
|
180
|
+
rect: { width: 150, height: 100 },
|
|
169
181
|
fillColor: WebColors.Blue,
|
|
170
182
|
});
|
|
171
183
|
chooseRectangleScene.addChild(blueRect);
|
|
172
184
|
const correctMessage = new Label({
|
|
173
185
|
text: "CORRECT!",
|
|
174
|
-
position:
|
|
186
|
+
position: { x: 200, y: 500 },
|
|
175
187
|
});
|
|
176
188
|
|
|
177
189
|
const chooseMessage = new Label({
|
|
178
190
|
text: "Choose the red rectangle",
|
|
179
|
-
position:
|
|
191
|
+
position: { x: 200, y: 200 },
|
|
180
192
|
});
|
|
181
193
|
chooseRectangleScene.addChild(chooseMessage);
|
|
182
194
|
|
|
@@ -184,32 +196,34 @@ class {{className}} extends Game {
|
|
|
184
196
|
chooseRectangleScene.addChild(correctMessage);
|
|
185
197
|
const wrongMessage = new Label({
|
|
186
198
|
text: "WRONG!",
|
|
187
|
-
position:
|
|
199
|
+
position: {x: 200, y: 500 },
|
|
188
200
|
});
|
|
189
201
|
|
|
190
202
|
wrongMessage.hidden = true;
|
|
191
203
|
chooseRectangleScene.addChild(wrongMessage);
|
|
192
204
|
|
|
193
|
-
// chooseRectangleScene.
|
|
194
|
-
// time this scene is shown. Within
|
|
205
|
+
// chooseRectangleScene.onSetup() is passed a callback that is executed each
|
|
206
|
+
// time this scene is shown. Within onSetup(), We will randomly decide on
|
|
195
207
|
// what side the red rectangle is shown
|
|
196
|
-
chooseRectangleScene.
|
|
208
|
+
chooseRectangleScene.onSetup(() => {
|
|
209
|
+
let responseTime = NaN;
|
|
197
210
|
let redOnLeft = true;
|
|
198
211
|
if (Math.random() > 0.5) {
|
|
199
212
|
redOnLeft = false;
|
|
200
213
|
}
|
|
201
214
|
|
|
202
215
|
if (redOnLeft) {
|
|
203
|
-
redRect.position =
|
|
204
|
-
blueRect.position =
|
|
216
|
+
redRect.position = { x: 100, y: 300 };
|
|
217
|
+
blueRect.position = { x: 300, y: 300 };
|
|
205
218
|
} else {
|
|
206
|
-
redRect.position =
|
|
207
|
-
blueRect.position =
|
|
219
|
+
redRect.position = { x: 300, y: 300 };
|
|
220
|
+
blueRect.position = { x: 100, y: 300 };;
|
|
208
221
|
}
|
|
209
222
|
|
|
210
223
|
// helper function to record the user's choice and
|
|
211
224
|
// decide if we are done
|
|
212
225
|
function recordUserInput(choseRedRect: boolean) {
|
|
226
|
+
game.addTrialData("responseTime", responseTime);
|
|
213
227
|
game.addTrialData("correct", choseRedRect);
|
|
214
228
|
if (choseRedRect) {
|
|
215
229
|
game.addTrialData("colorChosen", "red");
|
|
@@ -231,6 +245,7 @@ class {{className}} extends Game {
|
|
|
231
245
|
Action.Sequence([
|
|
232
246
|
Action.Custom({
|
|
233
247
|
callback: () => {
|
|
248
|
+
responseTime = Timer.elapsed("rt");
|
|
234
249
|
// once a choice is made, don't allow additional taps
|
|
235
250
|
redRect.isUserInteractionEnabled = false;
|
|
236
251
|
blueRect.isUserInteractionEnabled = false;
|
|
@@ -264,6 +279,7 @@ class {{className}} extends Game {
|
|
|
264
279
|
Action.Sequence([
|
|
265
280
|
Action.Custom({
|
|
266
281
|
callback: () => {
|
|
282
|
+
responseTime = Timer.elapsed("rt");
|
|
267
283
|
redRect.isUserInteractionEnabled = false;
|
|
268
284
|
blueRect.isUserInteractionEnabled = false;
|
|
269
285
|
},
|
|
@@ -287,25 +303,25 @@ class {{className}} extends Game {
|
|
|
287
303
|
});
|
|
288
304
|
});
|
|
289
305
|
|
|
306
|
+
chooseRectangleScene.onAppear(() => {
|
|
307
|
+
Timer.removeAll();
|
|
308
|
+
Timer.start("rt");
|
|
309
|
+
});
|
|
310
|
+
|
|
290
311
|
const endScene = new Scene();
|
|
291
312
|
game.addScene(endScene);
|
|
292
313
|
const doneLabel = new Label({
|
|
293
|
-
text: `This will be reassigned in the
|
|
294
|
-
position:
|
|
314
|
+
text: `This will be reassigned in the onSetup() callback. If you see this, something went wrong!`,
|
|
315
|
+
position: { x: 200, y: 300},
|
|
295
316
|
});
|
|
296
317
|
endScene.addChild(doneLabel);
|
|
297
318
|
|
|
298
319
|
const startOverButton = new Button({
|
|
299
320
|
text: "Start over",
|
|
300
|
-
position:
|
|
321
|
+
position: { x: 200, y: 600 },
|
|
301
322
|
});
|
|
302
323
|
startOverButton.isUserInteractionEnabled = true;
|
|
303
324
|
startOverButton.onTapDown(() => {
|
|
304
|
-
// in the setup() for the end scene, we animate the smiley sprite with
|
|
305
|
-
// a move action. if the user taps the start over button before the
|
|
306
|
-
// animation is completed, we should remove it by calling
|
|
307
|
-
// removeAllActions()
|
|
308
|
-
smileySprite.removeAllActions();
|
|
309
325
|
game.initData();
|
|
310
326
|
game.presentScene(getReadyScene);
|
|
311
327
|
});
|
|
@@ -313,7 +329,7 @@ class {{className}} extends Game {
|
|
|
313
329
|
|
|
314
330
|
const exitButton = new Button({
|
|
315
331
|
text: "Exit",
|
|
316
|
-
position:
|
|
332
|
+
position: { x: 200, y: 675 },
|
|
317
333
|
});
|
|
318
334
|
exitButton.isUserInteractionEnabled = true;
|
|
319
335
|
exitButton.onTapDown(() => {
|
|
@@ -325,69 +341,14 @@ class {{className}} extends Game {
|
|
|
325
341
|
});
|
|
326
342
|
endScene.addChild(exitButton);
|
|
327
343
|
|
|
328
|
-
|
|
329
|
-
endScene.addChild(smileySprite);
|
|
330
|
-
|
|
331
|
-
endScene.setup(() => {
|
|
344
|
+
endScene.onSetup(() => {
|
|
332
345
|
doneLabel.text = `You did ${game.trialIndex} trials. You're done!`;
|
|
333
|
-
|
|
334
|
-
// example of how to position a sprite and create an action to move it
|
|
335
|
-
smileySprite.position = new Point(200, 500);
|
|
336
|
-
smileySprite.run(
|
|
337
|
-
Action.Move({ point: new Point(200, 100), duration: 3000 })
|
|
338
|
-
);
|
|
339
346
|
});
|
|
340
347
|
|
|
341
348
|
game.entryScene = "instructions-01";
|
|
342
349
|
}
|
|
343
350
|
}
|
|
344
351
|
|
|
345
|
-
// ===========================================================================
|
|
346
|
-
|
|
347
|
-
//#region to support m2c2kit in Android WebView
|
|
348
|
-
/** When running within an Android WebView, the below defines how the session
|
|
349
|
-
* can communicate events back to the Android app. Note: names of this Android
|
|
350
|
-
* namespace and its functions must match the corresponding Android code
|
|
351
|
-
* in addJavascriptInterface() and @JavascriptInterface */
|
|
352
|
-
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
353
|
-
declare namespace Android {
|
|
354
|
-
function onGameTrialComplete(gameTrialEventAsString: string): void;
|
|
355
|
-
function onGameLifecycleChange(gameLifecycleEventAsString: string): void;
|
|
356
|
-
function onSessionLifecycleChange(
|
|
357
|
-
sessionLifecycleEventAsString: string
|
|
358
|
-
): void;
|
|
359
|
-
/** if the Android native app will control the session execution and be
|
|
360
|
-
* able to set custom game paraemters (which is probably what you want),
|
|
361
|
-
* be sure that sessionManualStart() in the native code returns true */
|
|
362
|
-
function sessionManualStart(): boolean;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function contextIsAndroidWebView(): boolean {
|
|
366
|
-
return typeof Android !== "undefined";
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
function sendEventToAndroid(event: EventBase) {
|
|
370
|
-
switch (event.eventType) {
|
|
371
|
-
case EventType.sessionLifecycle: {
|
|
372
|
-
Android.onSessionLifecycleChange(JSON.stringify(event));
|
|
373
|
-
break;
|
|
374
|
-
}
|
|
375
|
-
case EventType.gameTrial: {
|
|
376
|
-
Android.onGameTrialComplete(JSON.stringify(event));
|
|
377
|
-
break;
|
|
378
|
-
}
|
|
379
|
-
case EventType.gameLifecycle: {
|
|
380
|
-
Android.onGameLifecycleChange(JSON.stringify(event));
|
|
381
|
-
break;
|
|
382
|
-
}
|
|
383
|
-
default:
|
|
384
|
-
throw new Error(
|
|
385
|
-
`attempt to send unknown event ${event.eventType} to Android`
|
|
386
|
-
);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
//#endregion
|
|
390
|
-
|
|
391
352
|
const game1 = new {{className}}();
|
|
392
353
|
// default was 3 trials; this is how we can specify a different value
|
|
393
354
|
game1.setParameters({ TrialNum: 2 });
|
|
@@ -395,68 +356,71 @@ game1.setParameters({ TrialNum: 2 });
|
|
|
395
356
|
const session = new Session({
|
|
396
357
|
activities: [game1],
|
|
397
358
|
sessionCallbacks: {
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
//#endregion
|
|
359
|
+
/**
|
|
360
|
+
* onSessionLifecycleChange() will be called on events such
|
|
361
|
+
* as when the session initialization is complete or when it
|
|
362
|
+
* ends.
|
|
363
|
+
*
|
|
364
|
+
* Once initialized, the session will automatically start,
|
|
365
|
+
* unless we're running in an Android WebView AND a manual start
|
|
366
|
+
* is desired.
|
|
367
|
+
*/
|
|
368
|
+
onSessionLifecycleChange: (ev: SessionLifecycleEvent) => {
|
|
369
|
+
if (ev.initialized) {
|
|
412
370
|
session.start();
|
|
413
371
|
}
|
|
414
|
-
if (
|
|
372
|
+
if (ev.ended) {
|
|
415
373
|
console.log("session ended");
|
|
416
|
-
//#region to support m2c2kit in Android WebView
|
|
417
|
-
if (contextIsAndroidWebView()) {
|
|
418
|
-
sendEventToAndroid(event);
|
|
419
|
-
}
|
|
420
|
-
//#endregion
|
|
421
374
|
}
|
|
422
375
|
},
|
|
423
376
|
},
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
377
|
+
activityCallbacks: {
|
|
378
|
+
/**
|
|
379
|
+
* onActivityDataCreate() is where you insert code to post data to an API
|
|
380
|
+
* or interop with a native function in the host app.
|
|
381
|
+
*
|
|
382
|
+
* newData is the data that was just generated by the completed trial
|
|
383
|
+
* data is all the data, cumulative of all trials, that have been generated.
|
|
384
|
+
*
|
|
385
|
+
* We separate out newData from data in case you want to alter the execution
|
|
386
|
+
* based on the most recent trial, e.g., maybe you want to stop after
|
|
387
|
+
* a certain user behavior or performance threshold in the just completed
|
|
388
|
+
* trial.
|
|
389
|
+
*/
|
|
390
|
+
onActivityDataCreate: (ev: ActivityDataEvent) => {
|
|
391
|
+
console.log(`********** trial complete`);
|
|
392
|
+
console.log("newData: " + JSON.stringify(ev.newData));
|
|
393
|
+
console.log("newData schema: " + JSON.stringify(ev.newDataSchema));
|
|
394
|
+
console.log("data: " + JSON.stringify(ev.data));
|
|
395
|
+
console.log("data schema: " + JSON.stringify(ev.dataSchema));
|
|
396
|
+
console.log(
|
|
397
|
+
"activity parameters: " + JSON.stringify(ev.activityConfiguration)
|
|
398
|
+
);
|
|
438
399
|
},
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
400
|
+
/**
|
|
401
|
+
* onActivityLifecycleChange() notifies us when an activity, such
|
|
402
|
+
* as an assessment or a survey, has completed. Usually, however,
|
|
403
|
+
* we want to know when all the activities are done, so we'll
|
|
404
|
+
* look for the session ending via onSessionLifecycleChange
|
|
405
|
+
*/
|
|
406
|
+
onActivityLifecycleChange: (ev: ActivityLifecycleEvent) => {
|
|
407
|
+
if (ev.ended) {
|
|
408
|
+
console.log(`ended activity ${ev.name}`);
|
|
442
409
|
if (session.nextActivity) {
|
|
443
410
|
session.advanceToNextActivity();
|
|
444
411
|
} else {
|
|
445
412
|
session.end();
|
|
446
413
|
}
|
|
447
|
-
//#region to support m2c2kit in Android WebView
|
|
448
|
-
if (contextIsAndroidWebView()) {
|
|
449
|
-
sendEventToAndroid(event);
|
|
450
|
-
}
|
|
451
|
-
//#endregion
|
|
452
414
|
}
|
|
453
415
|
},
|
|
454
416
|
},
|
|
455
417
|
});
|
|
456
418
|
|
|
457
|
-
/**
|
|
419
|
+
/**
|
|
420
|
+
* Make session also available on window in case we want to control
|
|
458
421
|
* the session through another means, such as other javascript or
|
|
459
|
-
* browser code, or the Android WebView loadUrl() method
|
|
422
|
+
* browser code, or the Android WebView loadUrl() method
|
|
423
|
+
* */
|
|
460
424
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
461
425
|
(window as unknown as any).session = session;
|
|
462
426
|
session.init();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m2c2kit/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "m2c2kit command line interface",
|
|
5
5
|
"module": "dist/cli.js",
|
|
6
6
|
"files": [
|
|
@@ -17,28 +17,28 @@
|
|
|
17
17
|
"build": "npm run clean && npm run compile && npm run copy-files && npm run write-dotenv",
|
|
18
18
|
"compile": "tsc",
|
|
19
19
|
"clean": "rimraf dist/ && rimraf build/",
|
|
20
|
-
"copy-files": "copyfiles -f build/src/cli.js dist && copyfiles templates/* fonts/**/* dist/",
|
|
20
|
+
"copy-files": "copyfiles -f build/src/cli.js dist && copyfiles scripts/* templates/* fonts/**/* dist/",
|
|
21
21
|
"write-dotenv": "node write-dotenv.js"
|
|
22
22
|
},
|
|
23
23
|
"author": "",
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"axios": "0.24.0",
|
|
27
|
-
"chalk": "5.0.
|
|
27
|
+
"chalk": "5.0.1",
|
|
28
28
|
"conf": "10.1.1",
|
|
29
29
|
"form-data": "4.0.0",
|
|
30
30
|
"handlebars": "4.7.7",
|
|
31
|
-
"ora": "6.0
|
|
31
|
+
"ora": "6.1.0",
|
|
32
32
|
"prompts": "2.4.2",
|
|
33
33
|
"yargs": "17.3.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@types/node": "17.0.
|
|
36
|
+
"@types/node": "17.0.21",
|
|
37
37
|
"@types/prompts": "2.0.14",
|
|
38
|
-
"@types/yargs": "17.0.
|
|
38
|
+
"@types/yargs": "17.0.9",
|
|
39
39
|
"copyfiles": "2.4.1",
|
|
40
40
|
"rimraf": "3.0.2",
|
|
41
41
|
"tslib": "2.3.1",
|
|
42
|
-
"typescript": "4.
|
|
42
|
+
"typescript": "4.6.2"
|
|
43
43
|
}
|
|
44
44
|
}
|