@bongos/core 1.25.6 → 1.25.7
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/.bongos-core.json +37 -27
- package/docs/copy-inventory.md +9 -8
- package/docs/copy-registry.json +20 -11
- package/docs/module-api-changelog.md +2 -2
- package/docs/page-readings.json +37 -37
- package/modules/hall-ui/public/shell-game.js +98 -2
- package/modules/hall-ui/public/style.css +59 -0
- package/modules/hall-ui/public/visor.css +11 -0
- package/modules/hall-ui/public/visor.js +14 -5
- package/modules/hall-ui/records/game-menu.md +22 -0
- package/modules/hall-ui/records/game-mode.md +2 -2
- package/modules/hall-ui/records/options-menu.md +1 -1
- package/modules/hall-ui/records/start-screen.md +2 -2
- package/modules/hall-ui/records/visor.md +4 -0
- package/modules/ui-design/public/brand.html +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +16 -1
- package/src/module-api.js +1 -1
- package/tests/hall_game_menu.mjs +195 -0
- package/tests/hall_options_menu.mjs +4 -1
- package/tests/hall_visor.mjs +40 -5
package/docs/page-readings.json
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
"adr": "0341 D3",
|
|
6
6
|
"reread": "node scripts/bongos/page-reader.js --stale",
|
|
7
7
|
"how": ["Generated by node scripts/bongos/page-reader.js (BV2.TW04, task 1004315; ADR 0341 D3). Do not hand-edit.","One entry per page of docs/page-inventory.json. Lines are in page order: the default state first, and a line only another state shows sits where that state shows it, with its state named.","placement: placed = a docs/copy-registry.json row renders it (file, line, string_id); shared = shell text every page of the surface carries (top bar, sidebar, footer), with its row when the registry has one; unplaced = the registry cannot place it (a rewrite becomes an engineer task, ADR 0341 D4).","text keeps {…} where the registry row has a hole, or where a value the page read from its API was filled in. A string that is only such data is counted under omitted.data, not listed.","reading_hash is over the non-shared lines (key, section, text); files_hash is over the page's inventory files. --check compares files_hash only and never opens a browser.","Rendered through the hall-preview harness (hall) and the ui-design kit stub (landing, status), at 1280x800 with the clock pinned, so a reading is the fixture world's page."],
|
|
8
|
-
"counts": {"pages":45,"lines":4408,"placed":
|
|
8
|
+
"counts": {"pages":45,"lines":4408,"placed":1634,"shared":369,"unplaced":2405,"omitted_data":2980},
|
|
9
9
|
"pages": [
|
|
10
10
|
{
|
|
11
11
|
"id": "builders:ai-studio",
|
|
12
12
|
"surface": "builders",
|
|
13
13
|
"title": "Studio",
|
|
14
14
|
"states_read": ["pick","describe","make","waiting","result","result-own","failed","balance","balance-all","out"],
|
|
15
|
-
"files_hash": "
|
|
15
|
+
"files_hash": "3d35f6429c350fff",
|
|
16
16
|
"reading_hash": "d9e0e85bcee4aff4",
|
|
17
17
|
"counts": {"lines":106,"placed":41,"shared":7,"unplaced":58},
|
|
18
18
|
"omitted": {"data":17},
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"surface": "builders",
|
|
132
132
|
"title": "Repo Atlas",
|
|
133
133
|
"states_read": ["map","truth","detail","index","out"],
|
|
134
|
-
"files_hash": "
|
|
134
|
+
"files_hash": "edfe4cc950edf0d4",
|
|
135
135
|
"reading_hash": "6934dead335b2507",
|
|
136
136
|
"counts": {"lines":25,"placed":14,"shared":7,"unplaced":4},
|
|
137
137
|
"omitted": {"data":5},
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
"surface": "builders",
|
|
170
170
|
"title": "Blockers",
|
|
171
171
|
"states_read": ["default"],
|
|
172
|
-
"files_hash": "
|
|
172
|
+
"files_hash": "f922e0329e8eb75f",
|
|
173
173
|
"reading_hash": "60d73d854ced958a",
|
|
174
174
|
"counts": {"lines":36,"placed":17,"shared":7,"unplaced":12},
|
|
175
175
|
"omitted": {"data":51},
|
|
@@ -218,7 +218,7 @@
|
|
|
218
218
|
"surface": "builders",
|
|
219
219
|
"title": "Board Room",
|
|
220
220
|
"states_read": ["room","out","sitting-meta","objection-form"],
|
|
221
|
-
"files_hash": "
|
|
221
|
+
"files_hash": "4e378a78e17d9366",
|
|
222
222
|
"reading_hash": "0260b797b8dc1526",
|
|
223
223
|
"counts": {"lines":52,"placed":21,"shared":7,"unplaced":24},
|
|
224
224
|
"omitted": {"data":17},
|
|
@@ -283,7 +283,7 @@
|
|
|
283
283
|
"surface": "builders",
|
|
284
284
|
"title": "The city",
|
|
285
285
|
"states_read": ["city","fullscreen","focus","pins","living","card","card-ask"],
|
|
286
|
-
"files_hash": "
|
|
286
|
+
"files_hash": "914cb0dece28a131",
|
|
287
287
|
"reading_hash": "277096d903879a57",
|
|
288
288
|
"counts": {"lines":26,"placed":9,"shared":6,"unplaced":11},
|
|
289
289
|
"omitted": {"data":7},
|
|
@@ -322,7 +322,7 @@
|
|
|
322
322
|
"surface": "builders",
|
|
323
323
|
"title": "Collab",
|
|
324
324
|
"states_read": ["board","out"],
|
|
325
|
-
"files_hash": "
|
|
325
|
+
"files_hash": "3a06128fed49c33c",
|
|
326
326
|
"reading_hash": "e6452bf92231656f",
|
|
327
327
|
"counts": {"lines":82,"placed":36,"shared":6,"unplaced":40},
|
|
328
328
|
"omitted": {"data":23},
|
|
@@ -417,7 +417,7 @@
|
|
|
417
417
|
"surface": "builders",
|
|
418
418
|
"title": "Commands",
|
|
419
419
|
"states_read": ["in","out"],
|
|
420
|
-
"files_hash": "
|
|
420
|
+
"files_hash": "706fcc645c941fde",
|
|
421
421
|
"reading_hash": "ecc452689a8ee9d7",
|
|
422
422
|
"counts": {"lines":71,"placed":49,"shared":7,"unplaced":15},
|
|
423
423
|
"omitted": {"data":177},
|
|
@@ -501,7 +501,7 @@
|
|
|
501
501
|
"surface": "builders",
|
|
502
502
|
"title": "Copy desk",
|
|
503
503
|
"states_read": ["queue","out","search","composer","closer","proposer"],
|
|
504
|
-
"files_hash": "
|
|
504
|
+
"files_hash": "d9a01382c115a92a",
|
|
505
505
|
"reading_hash": "3819ef6fa8f6fb7c",
|
|
506
506
|
"counts": {"lines":72,"placed":36,"shared":7,"unplaced":29},
|
|
507
507
|
"omitted": {"data":94},
|
|
@@ -586,7 +586,7 @@
|
|
|
586
586
|
"surface": "builders",
|
|
587
587
|
"title": "Deploy",
|
|
588
588
|
"states_read": ["work","out"],
|
|
589
|
-
"files_hash": "
|
|
589
|
+
"files_hash": "b39bb32c17c12975",
|
|
590
590
|
"reading_hash": "3770e8b2fa56bee1",
|
|
591
591
|
"counts": {"lines":14,"placed":5,"shared":7,"unplaced":2},
|
|
592
592
|
"omitted": {"data":5},
|
|
@@ -613,7 +613,7 @@
|
|
|
613
613
|
"surface": "builders",
|
|
614
614
|
"title": "The sky",
|
|
615
615
|
"states_read": ["tour","sky","wells","ledger","full","full-back","out"],
|
|
616
|
-
"files_hash": "
|
|
616
|
+
"files_hash": "c8473c8bd6bfcff3",
|
|
617
617
|
"reading_hash": "4a879397a84631e3",
|
|
618
618
|
"counts": {"lines":50,"placed":25,"shared":6,"unplaced":19},
|
|
619
619
|
"omitted": {"data":10},
|
|
@@ -676,7 +676,7 @@
|
|
|
676
676
|
"surface": "builders",
|
|
677
677
|
"title": "Goals",
|
|
678
678
|
"states_read": ["list","filters","cards","detail","dependencies","out","uat","uat-panel","author"],
|
|
679
|
-
"files_hash": "
|
|
679
|
+
"files_hash": "ac39a09e8a923863",
|
|
680
680
|
"reading_hash": "13a5d07b3804b627",
|
|
681
681
|
"counts": {"lines":187,"placed":61,"shared":7,"unplaced":119},
|
|
682
682
|
"omitted": {"data":315},
|
|
@@ -876,7 +876,7 @@
|
|
|
876
876
|
"surface": "builders",
|
|
877
877
|
"title": "Government",
|
|
878
878
|
"states_read": ["constitution","out","permissions","board","constitution-tab"],
|
|
879
|
-
"files_hash": "
|
|
879
|
+
"files_hash": "ea32e1399fe5b394",
|
|
880
880
|
"reading_hash": "37c6878d60447fd6",
|
|
881
881
|
"counts": {"lines":65,"placed":27,"shared":7,"unplaced":31},
|
|
882
882
|
"omitted": {"data":276},
|
|
@@ -954,9 +954,9 @@
|
|
|
954
954
|
"surface": "builders",
|
|
955
955
|
"title": "Builders' Hall",
|
|
956
956
|
"states_read": ["home","out","founding","genesis","decide","demo","votes"],
|
|
957
|
-
"files_hash": "
|
|
958
|
-
"reading_hash": "
|
|
959
|
-
"counts": {"lines":29,"placed":
|
|
957
|
+
"files_hash": "db319ffd04ab0951",
|
|
958
|
+
"reading_hash": "c5f4986bd90e2a2a",
|
|
959
|
+
"counts": {"lines":29,"placed":8,"shared":8,"unplaced":13},
|
|
960
960
|
"omitted": {"data":4},
|
|
961
961
|
"notes": ["founding: an action failed (page.focus: Timeout 6000ms exceeded.); read as it stood"],
|
|
962
962
|
"lines": [
|
|
@@ -982,7 +982,7 @@
|
|
|
982
982
|
{"key":"L0020","section":"{…}","text":"The city, {…} screen","placement":"unplaced"},
|
|
983
983
|
{"key":"L0021","section":"{…}","text":"Classic","placement":"unplaced"},
|
|
984
984
|
{"key":"L0022","section":"{…}","text":"The hall with its sidebar","placement":"unplaced"},
|
|
985
|
-
{"key":"L0023","section":"{…}","text":"
|
|
985
|
+
{"key":"L0023","section":"{…}","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232"},
|
|
986
986
|
{"key":"L0024","section":"Update the builders hall?","text":"Update the builders hall?","placement":"unplaced"},
|
|
987
987
|
{"key":"L0025","section":"Update the builders hall?","text":"A newer version of Bongos is ready, with the latest changes and bug fixes.","placement":"placed","file":"modules/hall-ui/public/update-pill.js","line":604,"string_id":"105876fd9038"},
|
|
988
988
|
{"key":"L0026","section":"Update the builders hall?","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","occurrences":3},
|
|
@@ -996,7 +996,7 @@
|
|
|
996
996
|
"surface": "builders",
|
|
997
997
|
"title": "Idea",
|
|
998
998
|
"states_read": ["record","missing"],
|
|
999
|
-
"files_hash": "
|
|
999
|
+
"files_hash": "3f72b14ed91b7803",
|
|
1000
1000
|
"reading_hash": "f7d644748c87e426",
|
|
1001
1001
|
"counts": {"lines":52,"placed":25,"shared":8,"unplaced":19},
|
|
1002
1002
|
"omitted": {"data":25},
|
|
@@ -1061,7 +1061,7 @@
|
|
|
1061
1061
|
"surface": "builders",
|
|
1062
1062
|
"title": "Ideas",
|
|
1063
1063
|
"states_read": ["compose","full","develop"],
|
|
1064
|
-
"files_hash": "
|
|
1064
|
+
"files_hash": "69f7665f4d823b05",
|
|
1065
1065
|
"reading_hash": "a62c05dcef3bf87f",
|
|
1066
1066
|
"counts": {"lines":68,"placed":34,"shared":7,"unplaced":27},
|
|
1067
1067
|
"omitted": {"data":118},
|
|
@@ -1142,7 +1142,7 @@
|
|
|
1142
1142
|
"surface": "builders",
|
|
1143
1143
|
"title": "Market Watch",
|
|
1144
1144
|
"states_read": ["desk","settings","out"],
|
|
1145
|
-
"files_hash": "
|
|
1145
|
+
"files_hash": "d85500e69e188b5f",
|
|
1146
1146
|
"reading_hash": "30512dda207b5ea6",
|
|
1147
1147
|
"counts": {"lines":23,"placed":11,"shared":7,"unplaced":5},
|
|
1148
1148
|
"omitted": {"data":5},
|
|
@@ -1178,7 +1178,7 @@
|
|
|
1178
1178
|
"surface": "builders",
|
|
1179
1179
|
"title": "Market Watch",
|
|
1180
1180
|
"states_read": ["dossier","out","propose","correct","filtered"],
|
|
1181
|
-
"files_hash": "
|
|
1181
|
+
"files_hash": "ea3c71cb05717cc8",
|
|
1182
1182
|
"reading_hash": "129bff28c4e4ed6d",
|
|
1183
1183
|
"counts": {"lines":24,"placed":12,"shared":7,"unplaced":5},
|
|
1184
1184
|
"omitted": {"data":5},
|
|
@@ -1215,7 +1215,7 @@
|
|
|
1215
1215
|
"surface": "builders",
|
|
1216
1216
|
"title": "Market Watch rules",
|
|
1217
1217
|
"states_read": ["in","scoring","names","propose","out"],
|
|
1218
|
-
"files_hash": "
|
|
1218
|
+
"files_hash": "6f513cf7cdfe92ae",
|
|
1219
1219
|
"reading_hash": "ca0c62e8dce51c8b",
|
|
1220
1220
|
"counts": {"lines":36,"placed":12,"shared":7,"unplaced":17},
|
|
1221
1221
|
"omitted": {"data":20},
|
|
@@ -1264,7 +1264,7 @@
|
|
|
1264
1264
|
"surface": "builders",
|
|
1265
1265
|
"title": "Modules",
|
|
1266
1266
|
"states_read": ["browse","search-empty","lens","details","out"],
|
|
1267
|
-
"files_hash": "
|
|
1267
|
+
"files_hash": "2d24a52c632cde42",
|
|
1268
1268
|
"reading_hash": "6a12e9306bba5622",
|
|
1269
1269
|
"counts": {"lines":59,"placed":29,"shared":7,"unplaced":23},
|
|
1270
1270
|
"omitted": {"data":107},
|
|
@@ -1336,7 +1336,7 @@
|
|
|
1336
1336
|
"surface": "builders",
|
|
1337
1337
|
"title": "Money",
|
|
1338
1338
|
"states_read": ["money","hosting","out"],
|
|
1339
|
-
"files_hash": "
|
|
1339
|
+
"files_hash": "6096846da3462763",
|
|
1340
1340
|
"reading_hash": "e355d5466b123e07",
|
|
1341
1341
|
"counts": {"lines":83,"placed":28,"shared":7,"unplaced":48},
|
|
1342
1342
|
"omitted": {"data":27},
|
|
@@ -1432,7 +1432,7 @@
|
|
|
1432
1432
|
"surface": "builders",
|
|
1433
1433
|
"title": "My agents",
|
|
1434
1434
|
"states_read": ["desk","factory","saved","what-it-knows","speciality-walk","speciality-forms","nobody"],
|
|
1435
|
-
"files_hash": "
|
|
1435
|
+
"files_hash": "9c2b1b8aaf468c84",
|
|
1436
1436
|
"reading_hash": "5347e0496b38727d",
|
|
1437
1437
|
"counts": {"lines":100,"placed":33,"shared":7,"unplaced":60},
|
|
1438
1438
|
"omitted": {"data":38},
|
|
@@ -1545,7 +1545,7 @@
|
|
|
1545
1545
|
"surface": "builders",
|
|
1546
1546
|
"title": "Primer",
|
|
1547
1547
|
"states_read": ["in","toc-open","jump","out"],
|
|
1548
|
-
"files_hash": "
|
|
1548
|
+
"files_hash": "40d793bc1f676419",
|
|
1549
1549
|
"reading_hash": "85790bd421e5c387",
|
|
1550
1550
|
"counts": {"lines":487,"placed":57,"shared":7,"unplaced":423},
|
|
1551
1551
|
"omitted": {"data":18},
|
|
@@ -2045,7 +2045,7 @@
|
|
|
2045
2045
|
"surface": "builders",
|
|
2046
2046
|
"title": "Profile",
|
|
2047
2047
|
"states_read": ["own","works","activity","yours","activity-artist","activity-artist-ideas","other","artist","artist-ideas","out"],
|
|
2048
|
-
"files_hash": "
|
|
2048
|
+
"files_hash": "2e5aad6962c3c8b3",
|
|
2049
2049
|
"reading_hash": "3ff8d703d17e8c2a",
|
|
2050
2050
|
"counts": {"lines":232,"placed":84,"shared":7,"unplaced":141},
|
|
2051
2051
|
"omitted": {"data":263},
|
|
@@ -2290,7 +2290,7 @@
|
|
|
2290
2290
|
"surface": "builders",
|
|
2291
2291
|
"title": "Project settings",
|
|
2292
2292
|
"states_read": ["default"],
|
|
2293
|
-
"files_hash": "
|
|
2293
|
+
"files_hash": "3dde20d38f2c06da",
|
|
2294
2294
|
"reading_hash": "283df27d0d5bfc1b",
|
|
2295
2295
|
"counts": {"lines":43,"placed":25,"shared":7,"unplaced":11},
|
|
2296
2296
|
"omitted": {"data":33},
|
|
@@ -2346,7 +2346,7 @@
|
|
|
2346
2346
|
"surface": "builders",
|
|
2347
2347
|
"title": "Builders",
|
|
2348
2348
|
"states_read": ["roster","artists","search","out"],
|
|
2349
|
-
"files_hash": "
|
|
2349
|
+
"files_hash": "fd4aafc69104eed7",
|
|
2350
2350
|
"reading_hash": "665ac2e36339f5d3",
|
|
2351
2351
|
"counts": {"lines":56,"placed":17,"shared":7,"unplaced":32},
|
|
2352
2352
|
"omitted": {"data":137},
|
|
@@ -2415,7 +2415,7 @@
|
|
|
2415
2415
|
"surface": "builders",
|
|
2416
2416
|
"title": "Options",
|
|
2417
2417
|
"states_read": ["account","access","preferences","install-reports","sound","update"],
|
|
2418
|
-
"files_hash": "
|
|
2418
|
+
"files_hash": "6f61674891ca294c",
|
|
2419
2419
|
"reading_hash": "898a13fda24c3c90",
|
|
2420
2420
|
"counts": {"lines":162,"placed":104,"shared":7,"unplaced":51},
|
|
2421
2421
|
"omitted": {"data":23},
|
|
@@ -2590,7 +2590,7 @@
|
|
|
2590
2590
|
"surface": "builders",
|
|
2591
2591
|
"title": "The street",
|
|
2592
2592
|
"states_read": ["street","fullscreen","card","focus","here","inside-rules","inside-disputes","inside-people","inside-planning","inside-automation","inside-review","inside-release","inside-treasury","floor","amend","district","desk","desk-facts","desk-quiet","desk-people-builders","desk-people-tier","desk-disputes","desk-automation-goals","desk-release-core","desk-rules","desk-rules-category","desk-planning-priorities","desk-planning-ideas","desk-planning-blockers","pins","pins-pager","living","deck","deck-treasury","sitting","object","voted","admission","settled","blocker","blocker-more","report","report-more","core","core-more","recheck","recheck-more","idea","idea-more","queue","queue-more","automation","automation-more"],
|
|
2593
|
-
"files_hash": "
|
|
2593
|
+
"files_hash": "0824158dfe86879b",
|
|
2594
2594
|
"reading_hash": "e788e6bf4be8d68c",
|
|
2595
2595
|
"counts": {"lines":325,"placed":54,"shared":6,"unplaced":265},
|
|
2596
2596
|
"omitted": {"data":240},
|
|
@@ -2928,7 +2928,7 @@
|
|
|
2928
2928
|
"surface": "builders",
|
|
2929
2929
|
"title": "Studio",
|
|
2930
2930
|
"states_read": ["home","out","flow","flow-pick","status","words-offer","words-edit","reviews","full","full-back","approvals","approvals-before","approvals-phone","approvals-note","approved","sent-back","approvals-page"],
|
|
2931
|
-
"files_hash": "
|
|
2931
|
+
"files_hash": "b5217f22546d2ca2",
|
|
2932
2932
|
"reading_hash": "c4e3b4188c1db755",
|
|
2933
2933
|
"counts": {"lines":51,"placed":29,"shared":7,"unplaced":15},
|
|
2934
2934
|
"omitted": {"data":23},
|
|
@@ -2992,7 +2992,7 @@
|
|
|
2992
2992
|
"surface": "builders",
|
|
2993
2993
|
"title": "Task",
|
|
2994
2994
|
"states_read": ["record","from-goal","missing"],
|
|
2995
|
-
"files_hash": "
|
|
2995
|
+
"files_hash": "9a949acc81a483c6",
|
|
2996
2996
|
"reading_hash": "8dd803b6934e6388",
|
|
2997
2997
|
"counts": {"lines":151,"placed":46,"shared":9,"unplaced":96},
|
|
2998
2998
|
"omitted": {"data":111},
|
|
@@ -3156,7 +3156,7 @@
|
|
|
3156
3156
|
"surface": "builders",
|
|
3157
3157
|
"title": "Your thinking",
|
|
3158
3158
|
"states_read": ["tour","sky","list","simple","full-idea","full","full-list","full-back","out"],
|
|
3159
|
-
"files_hash": "
|
|
3159
|
+
"files_hash": "109968f4f22ab7b4",
|
|
3160
3160
|
"reading_hash": "b73f848b46b0f9b8",
|
|
3161
3161
|
"counts": {"lines":50,"placed":25,"shared":6,"unplaced":19},
|
|
3162
3162
|
"omitted": {"data":10},
|
|
@@ -3219,7 +3219,7 @@
|
|
|
3219
3219
|
"surface": "builders",
|
|
3220
3220
|
"title": "Tweak a page",
|
|
3221
3221
|
"states_read": ["doc","typed","chrome","submitted","picking","out"],
|
|
3222
|
-
"files_hash": "
|
|
3222
|
+
"files_hash": "a9131745a366382f",
|
|
3223
3223
|
"reading_hash": "f521f8d9a7147557",
|
|
3224
3224
|
"counts": {"lines":26,"placed":18,"shared":2,"unplaced":6},
|
|
3225
3225
|
"omitted": {"data":19},
|
|
@@ -3258,7 +3258,7 @@
|
|
|
3258
3258
|
"surface": "builders",
|
|
3259
3259
|
"title": "Watch",
|
|
3260
3260
|
"states_read": ["board","out","operations","security","sessions","autobongos"],
|
|
3261
|
-
"files_hash": "
|
|
3261
|
+
"files_hash": "b6a3ff14b1b63837",
|
|
3262
3262
|
"reading_hash": "1961a0c06b9d8477",
|
|
3263
3263
|
"counts": {"lines":72,"placed":33,"shared":7,"unplaced":32},
|
|
3264
3264
|
"omitted": {"data":52},
|
|
@@ -3343,7 +3343,7 @@
|
|
|
3343
3343
|
"surface": "builders",
|
|
3344
3344
|
"title": "Tasks",
|
|
3345
3345
|
"states_read": ["ready","in-progress","backlog","completed","filters-open","out","founding"],
|
|
3346
|
-
"files_hash": "
|
|
3346
|
+
"files_hash": "fb251657db11b790",
|
|
3347
3347
|
"reading_hash": "e9b412d1ec59ceee",
|
|
3348
3348
|
"counts": {"lines":122,"placed":49,"shared":7,"unplaced":66},
|
|
3349
3349
|
"omitted": {"data":323},
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
{ label: 'The atlas', href: '/atlas' },
|
|
104
104
|
];
|
|
105
105
|
var TIPS = [
|
|
106
|
-
'Escape opens the
|
|
106
|
+
'Escape opens the game menu: options, log out and exit.',
|
|
107
107
|
'Every tower is a goal. It gains a floor each time work ships under it.',
|
|
108
108
|
'A crane marks a site someone worked on this week.',
|
|
109
109
|
'A salmon dot on a tower means something there is waiting on you.',
|
|
@@ -440,10 +440,103 @@
|
|
|
440
440
|
if (host && host.OTBOptions && typeof host.OTBOptions.escape === 'function') { host.OTBOptions.escape(); return; }
|
|
441
441
|
if (host && host.OTBOptionsOverlay && host.OTBOptionsOverlay.isOpen()) { host.OTBOptionsOverlay.close(); return; }
|
|
442
442
|
if (embedded) return;
|
|
443
|
-
|
|
443
|
+
if (menuOpen()) { closeMenu(); return; }
|
|
444
|
+
openMenu();
|
|
444
445
|
}, 0);
|
|
445
446
|
}
|
|
446
447
|
|
|
448
|
+
// ---------- the game menu (task 1005250) ----------
|
|
449
|
+
// Game mode has no sidebar, so it had no way to sign out or to quit. The last Escape (and
|
|
450
|
+
// the visor's Menu hint and the Actions sheet's last row) now opens ONE small menu over the
|
|
451
|
+
// place, as a game does: Options (the options window below), Change character, Log out,
|
|
452
|
+
// Exit game, Return to game. It is the hall's shared dialog (OTBDialog.bind): Escape, the
|
|
453
|
+
// scrim, the focus trap and the focus return are its. A new advanced action is one row in
|
|
454
|
+
// GAME_MENU and one line in onMenuClick. Rules: modules/hall-ui/records/game-menu.md.
|
|
455
|
+
var GAME_MENU = [
|
|
456
|
+
{ id: 'options', label: 'Options' },
|
|
457
|
+
{ id: 'character', label: 'Change character' },
|
|
458
|
+
// shell.js turns a click on any link to the logout address into the real sign-out
|
|
459
|
+
{ id: 'logout', label: 'Log out', href: '/api/bongos/auth/logout', gap: true },
|
|
460
|
+
{ id: 'exit', label: 'Exit game' },
|
|
461
|
+
{ id: 'return', label: 'Return to game', gap: true },
|
|
462
|
+
];
|
|
463
|
+
var menuEl = null, menuDlg = null;
|
|
464
|
+
function menuOpen() { return !!(menuDlg && menuDlg.isOpen()); }
|
|
465
|
+
function closeMenu() { if (menuOpen()) menuDlg.close(); }
|
|
466
|
+
// Change character is craft-mode.js's; a page without it shows no such row.
|
|
467
|
+
function menuRows() {
|
|
468
|
+
var C = window.OTBCraftMode;
|
|
469
|
+
return GAME_MENU.filter(function (m) { return m.id !== 'character' || !!(C && typeof C.changeCharacter === 'function'); });
|
|
470
|
+
}
|
|
471
|
+
function menuRowHtml(m) {
|
|
472
|
+
var attrs = ' class="game-menu__item' + (m.id === 'return' ? ' game-menu__item--lit' : '') + '" data-gm="' + m.id + '"';
|
|
473
|
+
return '<li' + (m.gap ? ' class="game-menu__gap"' : '') + '>' +
|
|
474
|
+
(m.href ? '<a' + attrs + ' href="' + esc(m.href) + '">' + esc(m.label) + '</a>' : '<button type="button"' + attrs + '>' + esc(m.label) + '</button>') + '</li>';
|
|
475
|
+
}
|
|
476
|
+
var exitTimer = 0;
|
|
477
|
+
// Any new word in the note (a fresh opening clears it) drops a pending Exit check, so an
|
|
478
|
+
// Exit pressed just before the menu was shut cannot speak into the next opening.
|
|
479
|
+
function menuSay(text) {
|
|
480
|
+
clearTimeout(exitTimer); exitTimer = 0;
|
|
481
|
+
var note = menuEl && menuEl.querySelector('.game-menu__note');
|
|
482
|
+
if (!note) return;
|
|
483
|
+
note.textContent = text;
|
|
484
|
+
note.hidden = !text;
|
|
485
|
+
}
|
|
486
|
+
// Exit closes the tab. A browser only lets a script close a tab a script opened, so when
|
|
487
|
+
// the tab is still here a moment later the menu says so (the start screen's Quit, again).
|
|
488
|
+
function exitGame() {
|
|
489
|
+
try { window.close(); } catch (_) { /* refused */ }
|
|
490
|
+
clearTimeout(exitTimer);
|
|
491
|
+
exitTimer = setTimeout(function () { exitTimer = 0; if (menuOpen()) menuSay('Your browser kept this tab open. Close it to quit.'); }, 300);
|
|
492
|
+
}
|
|
493
|
+
function onMenuClick(e) {
|
|
494
|
+
var el = e.target && e.target.closest ? e.target.closest('[data-gm]') : null;
|
|
495
|
+
var id = el ? el.getAttribute('data-gm') : '';
|
|
496
|
+
if (id === 'return') closeMenu();
|
|
497
|
+
else if (id === 'options') { closeMenu(); openOverlay(); }
|
|
498
|
+
else if (id === 'character') { closeMenu(); window.OTBCraftMode.changeCharacter(); }
|
|
499
|
+
else if (id === 'exit') exitGame();
|
|
500
|
+
else if (id === 'logout') menuSay('Logging out');
|
|
501
|
+
}
|
|
502
|
+
// The arrows walk the rows, as on the start screen (Tab is the dialog's own trap).
|
|
503
|
+
function onMenuKey(e) {
|
|
504
|
+
var step = e.key === 'ArrowDown' ? 1 : e.key === 'ArrowUp' ? -1 : 0;
|
|
505
|
+
if (!step || !menuEl) return;
|
|
506
|
+
var rows = Array.prototype.slice.call(menuEl.querySelectorAll('[data-gm]'));
|
|
507
|
+
if (!rows.length) return;
|
|
508
|
+
e.preventDefault();
|
|
509
|
+
var at = rows.indexOf(document.activeElement);
|
|
510
|
+
rows[(at + step + rows.length) % rows.length].focus();
|
|
511
|
+
}
|
|
512
|
+
function openMenu() {
|
|
513
|
+
try { buildMenu(); } catch (_) {
|
|
514
|
+
// No menu can be drawn here: the options, as before the game menu existed.
|
|
515
|
+
menuEl = null; menuDlg = null;
|
|
516
|
+
openOverlay();
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
function buildMenu() {
|
|
520
|
+
if (!menuEl) {
|
|
521
|
+
if (!window.OTBDialog || typeof window.OTBDialog.bind !== 'function') throw new Error('no dialog');
|
|
522
|
+
menuEl = document.createElement('div');
|
|
523
|
+
menuEl.className = 'game-menu';
|
|
524
|
+
menuEl.hidden = true;
|
|
525
|
+
menuEl.addEventListener('click', onMenuClick);
|
|
526
|
+
menuEl.addEventListener('keydown', onMenuKey);
|
|
527
|
+
menuEl.innerHTML = '<div class="game-menu__box" aria-labelledby="game-menu-title">' +
|
|
528
|
+
'<h2 class="game-menu__title" id="game-menu-title">Game menu</h2>' +
|
|
529
|
+
'<ul class="game-menu__items"></ul>' +
|
|
530
|
+
'<p class="game-menu__note" role="status" hidden></p></div>';
|
|
531
|
+
document.body.appendChild(menuEl);
|
|
532
|
+
menuDlg = window.OTBDialog.bind(menuEl, { panel: menuEl.querySelector('.game-menu__box'), lockClass: 'game-menu-open' });
|
|
533
|
+
}
|
|
534
|
+
// The rows are drawn at each opening: they follow what the page has, and the note starts empty.
|
|
535
|
+
menuEl.querySelector('.game-menu__items').innerHTML = menuRows().map(menuRowHtml).join('');
|
|
536
|
+
menuSay('');
|
|
537
|
+
menuDlg.open();
|
|
538
|
+
}
|
|
539
|
+
|
|
447
540
|
// ---------- the options window (game mode) ----------
|
|
448
541
|
// In game mode the options menu opens as a window OVER the place you are in, not
|
|
449
542
|
// as a page of its own, so the place stays drawn behind it and its colours show
|
|
@@ -527,6 +620,7 @@
|
|
|
527
620
|
function overlayHere() { return on() && !(document.body && document.body.getAttribute('data-page') === 'settings'); }
|
|
528
621
|
if (!embedded) {
|
|
529
622
|
window.OTBOptionsOverlay = { open: openOverlay, openProfile: openProfile, close: closeOverlay, isOpen: overlayOpen };
|
|
623
|
+
window.OTBGameMenu = { open: openMenu, close: closeMenu, isOpen: menuOpen };
|
|
530
624
|
// A link to the menu (the visor's Options row, the profile chip, the start
|
|
531
625
|
// screen's Options) opens the window in game mode instead of leaving the place.
|
|
532
626
|
if (document.addEventListener) document.addEventListener('click', function (e) {
|
|
@@ -537,6 +631,8 @@
|
|
|
537
631
|
try { to = new URL(a.getAttribute('href'), window.location.href); } catch (_) { return; }
|
|
538
632
|
if (to.origin !== window.location.origin || to.pathname.replace(/\.html$/, '') !== menuPath()) return;
|
|
539
633
|
e.preventDefault();
|
|
634
|
+
// the visor's Menu hint and the Actions sheet's last row: the game menu, not the options
|
|
635
|
+
if (a.getAttribute('data-game-menu') !== null) { openMenu(); return; }
|
|
540
636
|
var q = to.search.replace(/([?&])from=[^&#]*&?/, '$1').replace(/[?&]$/, '');
|
|
541
637
|
openOverlay(q + to.hash);
|
|
542
638
|
}, true);
|
|
@@ -313,6 +313,16 @@
|
|
|
313
313
|
/* THE PLATE ON THE SKY (task 1005196): words and controls that sit on the hour's sky stand
|
|
314
314
|
on a small plate of the night, sized to what it holds, never on a darkened sky. */
|
|
315
315
|
--night-plate: color-mix(in srgb, var(--bg) 88%, transparent);
|
|
316
|
+
/* THE SMOKED PANE (task 1005252, the owner's pick from the glass lab): a plate on the visor
|
|
317
|
+
blurs what is behind it, so a scene's own words and marks (a screenshot of the hall under
|
|
318
|
+
review carries a visor of its own) go soft instead of reading as a second visor. Lighter
|
|
319
|
+
than the plate, but the backdrop is dimmed too, so ice on it still holds AA over a white
|
|
320
|
+
sky; a lit top edge makes it a pane. Where blur is missing or less transparency is asked
|
|
321
|
+
for, the plate stays the night plate. */
|
|
322
|
+
--smoke: color-mix(in srgb, var(--bg) 62%, transparent);
|
|
323
|
+
--smoke-blur: blur(14px) saturate(.8) brightness(.85);
|
|
324
|
+
--smoke-sheen: linear-gradient(to bottom, color-mix(in srgb, var(--ink-soft) 16%, transparent), transparent 40%);
|
|
325
|
+
--smoke-edge: inset 0 1px 0 color-mix(in srgb, var(--ink-soft) 35%, transparent), inset 0 -1px 0 color-mix(in srgb, var(--bg) 60%, transparent);
|
|
316
326
|
--line-strong: 1.5px;
|
|
317
327
|
--helm-panel-w: 400px;
|
|
318
328
|
--helm-row: 60px;
|
|
@@ -504,6 +514,14 @@ html[data-faces="helm"] {
|
|
|
504
514
|
--font-body: var(--helm-body);
|
|
505
515
|
}
|
|
506
516
|
|
|
517
|
+
/* Less transparency asked for (task 1005252): the visor's smoked panes go back to plates of the
|
|
518
|
+
night. `html` lifts it over visor.css, which loads after this sheet. */
|
|
519
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
520
|
+
html .visor__place, html .visor__who, html .visor__hint, html .visor__progress-words {
|
|
521
|
+
background: var(--night-plate); box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
507
525
|
/* The Kill Switch Rule (DESIGN.md). Nothing escapes it, and no motion is
|
|
508
526
|
authored in JavaScript, because JavaScript motion escapes it. */
|
|
509
527
|
@media (prefers-reduced-motion: reduce) {
|
|
@@ -891,6 +909,9 @@ html[data-theme="dark"] .brand-mark__mark { --mark-ink: #e2e1e4; }
|
|
|
891
909
|
html[data-game="on"] .visor__hint:not([data-visor-sheet]) { display: none; }
|
|
892
910
|
html[data-game="on"] .visor__hint--sheet { min-width: 44px; justify-content: center; }
|
|
893
911
|
html[data-game="on"] .visor__hint--sheet .visor__dots { display: block; }
|
|
912
|
+
/* task 1005252: a phone keeps the night plate, not the smoked pane — a live blur under a HUD
|
|
913
|
+
that the scene pans beneath is the costly kind of drawing, and a phone has the weakest GPU */
|
|
914
|
+
html[data-game="on"] .visor__who, html[data-game="on"] .visor__hint { background: var(--night-plate); box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
|
|
894
915
|
html[data-game="on"] .visor__hint--sheet > :not(.visor__dots) { position: absolute; width: 1px; height: 1px; padding: 0; border: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
|
|
895
916
|
html[data-game="on"] .visor__main .visor__key { display: none; }
|
|
896
917
|
html[data-game="on"] .visor__sheet { bottom: calc(var(--visor-inset-bottom) + 112px); max-height: 60vh; }
|
|
@@ -1516,6 +1537,44 @@ html.opt-window-open { overflow: hidden; }
|
|
|
1516
1537
|
}
|
|
1517
1538
|
.opt-window__x:hover { color: var(--ink); background: var(--glass); }
|
|
1518
1539
|
.opt-window__x:focus-visible { outline: 0; box-shadow: var(--press-focus); }
|
|
1540
|
+
/* THE GAME MENU (shell-game.js openMenu, task 1005250): game mode's Escape. One small
|
|
1541
|
+
night panel over the place, its rows stacked as buttons in three runs (what you can
|
|
1542
|
+
open, leaving, going back); Return to game is the one lit row. */
|
|
1543
|
+
html.game-menu-open { overflow: hidden; }
|
|
1544
|
+
.game-menu { position: fixed; inset: 0; z-index: var(--z-modal); display: grid; place-items: center; }
|
|
1545
|
+
.game-menu[hidden] { display: none; }
|
|
1546
|
+
.game-menu::before { content: ''; position: absolute; inset: 0; background: var(--scrim); opacity: .33; pointer-events: none; }
|
|
1547
|
+
.game-menu__box {
|
|
1548
|
+
position: relative; box-sizing: border-box;
|
|
1549
|
+
width: min(300px, calc(100vw - 32px)); max-height: calc(100vh - 32px); overflow-y: auto;
|
|
1550
|
+
padding: var(--ds-space-md);
|
|
1551
|
+
background: var(--night-glass);
|
|
1552
|
+
border: var(--line-strong) solid var(--rule);
|
|
1553
|
+
border-radius: var(--press-radius);
|
|
1554
|
+
box-shadow: var(--ds-shadow-pop);
|
|
1555
|
+
}
|
|
1556
|
+
.game-menu__title {
|
|
1557
|
+
margin: 0 0 var(--ds-space-md); text-align: center;
|
|
1558
|
+
font-family: var(--name-face); font-size: var(--ds-text-xl); font-weight: var(--name-weight);
|
|
1559
|
+
letter-spacing: var(--name-space); text-transform: var(--name-case); color: var(--ink);
|
|
1560
|
+
}
|
|
1561
|
+
.game-menu__items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--ds-space-xs); }
|
|
1562
|
+
.game-menu__gap { margin-top: var(--ds-space-sm); }
|
|
1563
|
+
.game-menu__item {
|
|
1564
|
+
display: flex; align-items: center; justify-content: center; box-sizing: border-box;
|
|
1565
|
+
width: 100%; min-height: 40px; padding: var(--ds-space-hair) var(--ds-space-sm);
|
|
1566
|
+
background: var(--glass); color: var(--ink);
|
|
1567
|
+
border: var(--line) solid var(--rule); border-radius: var(--press-radius);
|
|
1568
|
+
font-family: var(--name-face); font-size: var(--ds-text-xl); font-weight: 400;
|
|
1569
|
+
letter-spacing: var(--name-space); text-transform: var(--name-case); text-align: center;
|
|
1570
|
+
text-decoration: none; cursor: pointer;
|
|
1571
|
+
}
|
|
1572
|
+
.game-menu__item:hover { color: var(--ink); border-color: var(--ink-soft); text-decoration: none; }
|
|
1573
|
+
.game-menu__item:focus-visible { outline: 0; box-shadow: var(--press-focus); }
|
|
1574
|
+
.game-menu__item--lit { background: var(--accent); color: var(--accent-on); border-color: transparent; font-weight: var(--name-weight-lit); }
|
|
1575
|
+
.game-menu__item--lit:hover { background: var(--accent-lift); color: var(--accent-on); border-color: transparent; }
|
|
1576
|
+
.game-menu__note { margin: var(--ds-space-sm) 0 0; font-size: var(--ds-text-md); line-height: 1.5; text-align: center; text-wrap: pretty; color: var(--ink); }
|
|
1577
|
+
.game-menu__note[hidden] { display: none; }
|
|
1519
1578
|
/* Said once on entering, since the choice is remembered and a page can open in it. */
|
|
1520
1579
|
.fullscreen-hint {
|
|
1521
1580
|
position: fixed;
|
|
@@ -79,6 +79,17 @@ html[data-game="on"] .visor:not([hidden]) {
|
|
|
79
79
|
font-size: var(--ds-text-xs); letter-spacing: var(--name-space); line-height: 1; color: var(--ink-soft);
|
|
80
80
|
padding: var(--ds-space-hair) var(--ds-space-xs); background: var(--night-plate); clip-path: var(--cut-path-sm);
|
|
81
81
|
}
|
|
82
|
+
/* smoked glass (task 1005252): where the browser can blur, each plate is a pane of smoked glass
|
|
83
|
+
that softens the scene behind it, so a scene that carries marks of its own (the review of a
|
|
84
|
+
hall screenshot) cannot line up with ours. Still sized to its words: the sky outside the
|
|
85
|
+
plates is untouched. Asking for less transparency puts the night plate back (style.css,
|
|
86
|
+
beside the Kill Switch, since the visor adds no media query of its own). */
|
|
87
|
+
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
|
|
88
|
+
.visor__place, .visor__who, .visor__hint, .visor__progress-words {
|
|
89
|
+
background: var(--smoke-sheen), var(--smoke); box-shadow: var(--smoke-edge);
|
|
90
|
+
-webkit-backdrop-filter: var(--smoke-blur); backdrop-filter: var(--smoke-blur);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
82
93
|
|
|
83
94
|
/* the foot row: you on the left, the one thing to press in the middle, the key hints on the
|
|
84
95
|
right. The two side groups lean in a little, as the glass curves. */
|
|
@@ -16,8 +16,9 @@
|
|
|
16
16
|
// went with it).
|
|
17
17
|
// Centre: your character's main action, the one accent button, with its key. Right: the
|
|
18
18
|
// quiet key hints, no boxes: your other actions and "Actions" (key A), which opens the
|
|
19
|
-
// sheet (your character's actions, then the keys of the place you are in, then
|
|
20
|
-
// a key of its own; Escape closes it).
|
|
19
|
+
// sheet (your character's actions, then the keys of the place you are in, then the game
|
|
20
|
+
// menu on a key of its own; Escape closes it). It is only in the sheet (task 1005248; the
|
|
21
|
+
// game menu since task 1005250).
|
|
21
22
|
// - every key comes from resolveKeys: one owner per key, never two (task 1005248).
|
|
22
23
|
//
|
|
23
24
|
// The rules it keeps (ADR 0399):
|
|
@@ -65,7 +66,9 @@
|
|
|
65
66
|
};
|
|
66
67
|
var SHEET_KEY = 'a';
|
|
67
68
|
var CLOSE_KEY = 'esc'; // shown once: the sheet's Close (Escape)
|
|
68
|
-
|
|
69
|
+
// The sheet's last row is the game menu (options, log out, exit; task 1005250): shell-game.js
|
|
70
|
+
// opens it for a data-game-menu link, and the address (the options) is the fallback.
|
|
71
|
+
var OPTIONS = { id: 'options', label: 'Game menu', key: 'm', href: '/settings' };
|
|
69
72
|
// Keys a scene binds on its own page (the sky's L 0 / ?, the gallery's F, the palette's K).
|
|
70
73
|
// A moved key never lands on one of them; a scene that declares one keeps it.
|
|
71
74
|
var AVOID = ['l', '0', '/', '?', 'f', 'k', '+', '-', '='];
|
|
@@ -377,7 +380,7 @@
|
|
|
377
380
|
'<button class="visor__close" type="button" data-visor-close aria-label="Close actions">' + keyHtml(CLOSE_KEY) + '</button></div>' +
|
|
378
381
|
'<p class="visor__cap">' + esc(NAMES[id]) + '</p><ul class="visor__rows">' + rows + '</ul>' +
|
|
379
382
|
(place ? '<p class="visor__cap">This place</p><ul class="visor__rows">' + place + '</ul>' : '') +
|
|
380
|
-
'<ul class="visor__rows"><li><a class="visor__row" data-visor-act="options" href="' + esc(hallHref(keys.options.href)) + '"><span>' + esc(keys.options.label) + '</span>' + keyHtml(keys.options.key) + '</a></li></ul>';
|
|
383
|
+
'<ul class="visor__rows"><li><a class="visor__row" data-visor-act="options" data-game-menu href="' + esc(hallHref(keys.options.href)) + '"><span>' + esc(keys.options.label) + '</span>' + keyHtml(keys.options.key) + '</a></li></ul>';
|
|
381
384
|
}
|
|
382
385
|
function shown() { return !!(root && !root.hidden); }
|
|
383
386
|
function render() {
|
|
@@ -460,6 +463,7 @@
|
|
|
460
463
|
return;
|
|
461
464
|
}
|
|
462
465
|
// Options opens the game's options window over the place when it can (shell-game.js)
|
|
466
|
+
if (a.id === OPTIONS.id && window.OTBGameMenu && typeof window.OTBGameMenu.open === 'function') { window.OTBGameMenu.open(); return; }
|
|
463
467
|
if (a.id === OPTIONS.id && window.OTBOptionsOverlay && typeof window.OTBOptionsOverlay.open === 'function') { window.OTBOptionsOverlay.open(); return; }
|
|
464
468
|
if (a.href) window.location.assign(hallHref(a.href));
|
|
465
469
|
}
|
|
@@ -475,6 +479,7 @@
|
|
|
475
479
|
if (t.closest('[data-visor-unfocus]')) { dropFocus(); return; }
|
|
476
480
|
if (t.closest('[data-visor-lead]')) { if (focus && focus.lead && !focus.lead.busy) { closeSheet(false); focus.lead.run(); } return; }
|
|
477
481
|
if (t.closest('[data-visor-sheet]')) { openSheet(); return; }
|
|
482
|
+
if (t.closest('[data-game-menu]')) { closeSheet(false); return; } // shell-game.js opens the menu
|
|
478
483
|
// You: your profile in the game's window, the place still drawn behind it. With no
|
|
479
484
|
// window (shell-game.js absent), the link opens the profile page.
|
|
480
485
|
if (t.closest('[data-visor-me]')) {
|
|
@@ -502,7 +507,11 @@
|
|
|
502
507
|
function busy() {
|
|
503
508
|
var html = document.documentElement;
|
|
504
509
|
if (html.classList && (html.classList.contains('craft-picker-open') || html.classList.contains('gs-open'))) return true;
|
|
505
|
-
|
|
510
|
+
// a dialog that is up: one bound once keeps aria-modal while it is hidden (the options
|
|
511
|
+
// window, the game menu), and a hidden one must not hold the keys (task 1005250)
|
|
512
|
+
var up = document.querySelectorAll('dialog[open], [aria-modal="true"]');
|
|
513
|
+
for (var i = 0; i < up.length; i++) if (!up[i].closest('[hidden]')) return true;
|
|
514
|
+
return false;
|
|
506
515
|
}
|
|
507
516
|
// Which action (or the sheet) a key press means, or null. Pure, for the tests.
|
|
508
517
|
function keyFor(id, e) {
|