@deeeed/metamask-harness 0.47.0 → 0.47.1

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.
@@ -1,325 +0,0 @@
1
- /*
2
- * Shared behaviour for the getting-started site: checklist progress, copy
3
- * buttons, platform filters, tabs, and the layer diagram. No dependencies, no
4
- * network, no tracking. Progress lives in localStorage under
5
- * `mmh.progress.<page>`, where <page> comes from body[data-progress-page].
6
- * Pages that share a namespace share their state (the How it works walkthrough and the V1
7
- * tutorial are deliberately the same checklist).
8
- */
9
- (function () {
10
- 'use strict';
11
-
12
- var KEY_PREFIX = 'mmh.progress.';
13
-
14
- /* ---------- storage (degrades to in-memory if localStorage is blocked) ---------- */
15
-
16
- var memory = {};
17
-
18
- function read(key) {
19
- try {
20
- var raw = window.localStorage.getItem(key);
21
- return raw ? JSON.parse(raw) : [];
22
- } catch (_err) {
23
- return memory[key] || [];
24
- }
25
- }
26
-
27
- function write(key, ids) {
28
- memory[key] = ids;
29
- try {
30
- window.localStorage.setItem(key, JSON.stringify(ids));
31
- } catch (_err) {
32
- /* Private mode or blocked storage: the page still works, just forgets. */
33
- }
34
- }
35
-
36
- /* ---------- checklist ---------- */
37
-
38
- function initChecklist() {
39
- var page = document.body.getAttribute('data-progress-page');
40
- var steps = [].slice.call(document.querySelectorAll('.step[data-step]'));
41
- if (!page || !steps.length) return;
42
-
43
- var key = KEY_PREFIX + page;
44
- var fill = document.querySelector('.progress-fill');
45
- var label = document.querySelector('.progress-label');
46
- var reset = document.querySelector('.progress-reset');
47
-
48
- function done() {
49
- return steps.filter(function (s) { return s.getAttribute('data-done') === '1'; });
50
- }
51
-
52
- function render() {
53
- var n = done().length;
54
- var pct = steps.length ? Math.round((n / steps.length) * 100) : 0;
55
- if (fill) {
56
- fill.style.width = pct + '%';
57
- fill.parentNode.setAttribute('aria-valuenow', String(pct));
58
- }
59
- if (label) {
60
- label.textContent = n === steps.length
61
- ? n + '/' + steps.length + ' — done'
62
- : n + '/' + steps.length + ' steps';
63
- }
64
- }
65
-
66
- function apply(ids) {
67
- steps.forEach(function (step) {
68
- var on = ids.indexOf(step.getAttribute('data-step')) !== -1;
69
- step.setAttribute('data-done', on ? '1' : '0');
70
- var box = step.querySelector('.step-check');
71
- if (box) box.checked = on;
72
- });
73
- render();
74
- }
75
-
76
- steps.forEach(function (step) {
77
- var box = step.querySelector('.step-check');
78
- if (!box) return;
79
- box.addEventListener('change', function () {
80
- var ids = read(key);
81
- var id = step.getAttribute('data-step');
82
- var at = ids.indexOf(id);
83
- if (box.checked && at === -1) ids.push(id);
84
- if (!box.checked && at !== -1) ids.splice(at, 1);
85
- write(key, ids);
86
- apply(ids);
87
- });
88
- });
89
-
90
- if (reset) {
91
- reset.addEventListener('click', function () {
92
- write(key, []);
93
- apply([]);
94
- });
95
- }
96
-
97
- /* Reflect edits made in another tab on the same namespace. */
98
- window.addEventListener('storage', function (e) {
99
- if (e.key === key) apply(read(key));
100
- });
101
-
102
- apply(read(key));
103
- }
104
-
105
- /* ---------- copy buttons ---------- */
106
-
107
- function textOf(block) {
108
- var pre = block.querySelector('pre');
109
- if (!pre) return '';
110
- var clone = pre.cloneNode(true);
111
- /* Shell prompt markers are decoration, never part of the command. */
112
- [].slice.call(clone.querySelectorAll('.p')).forEach(function (n) {
113
- n.parentNode.removeChild(n);
114
- });
115
- return clone.textContent.replace(/[ \t]+$/gm, '').trim();
116
- }
117
-
118
- function legacyCopy(text) {
119
- return new Promise(function (resolve, reject) {
120
- var ta = document.createElement('textarea');
121
- ta.value = text;
122
- ta.setAttribute('readonly', '');
123
- ta.style.position = 'fixed';
124
- ta.style.opacity = '0';
125
- document.body.appendChild(ta);
126
- ta.select();
127
- var ok = false;
128
- try { ok = document.execCommand('copy'); } catch (_err) { ok = false; }
129
- document.body.removeChild(ta);
130
- ok ? resolve() : reject(new Error('copy unavailable'));
131
- });
132
- }
133
-
134
- /*
135
- * The async clipboard needs a secure context AND permission; it rejects when
136
- * the document lacks focus. Fall through to the legacy path rather than
137
- * telling the reader to give up.
138
- */
139
- function copy(text) {
140
- if (navigator.clipboard && window.isSecureContext) {
141
- return navigator.clipboard.writeText(text).catch(function () {
142
- return legacyCopy(text);
143
- });
144
- }
145
- return legacyCopy(text);
146
- }
147
-
148
- function initCopy() {
149
- [].slice.call(document.querySelectorAll('.cmd')).forEach(function (block) {
150
- if (block.querySelector('.copy')) return;
151
- var btn = document.createElement('button');
152
- btn.type = 'button';
153
- btn.className = 'copy';
154
- btn.textContent = 'Copy';
155
- btn.setAttribute('aria-label', 'Copy to clipboard');
156
- btn.addEventListener('click', function () {
157
- copy(textOf(block)).then(function () {
158
- btn.textContent = 'Copied';
159
- btn.setAttribute('data-copied', '1');
160
- }, function () {
161
- btn.textContent = 'Press ⌘C';
162
- });
163
- setTimeout(function () {
164
- btn.textContent = 'Copy';
165
- btn.removeAttribute('data-copied');
166
- }, 1600);
167
- });
168
- block.appendChild(btn);
169
- });
170
- }
171
-
172
- /* ---------- click-to-copy table cells ---------- */
173
-
174
- /*
175
- * Reference tables put one command per cell, where a hovering copy button
176
- * would crowd the row. The cell itself is the button instead.
177
- */
178
- function initCellCopy() {
179
- var cells = [].slice.call(document.querySelectorAll('[data-copy-cells] td code'));
180
- cells.forEach(function (cell) {
181
- var original = cell.textContent;
182
- cell.tabIndex = 0;
183
- cell.setAttribute('role', 'button');
184
- cell.setAttribute('title', 'Click to copy');
185
- cell.classList.add('copyable');
186
-
187
- function run() {
188
- copy(original).then(function () {
189
- cell.textContent = 'Copied';
190
- cell.classList.add('copied');
191
- }, function () {
192
- cell.textContent = 'Press ⌘C';
193
- });
194
- setTimeout(function () {
195
- cell.textContent = original;
196
- cell.classList.remove('copied');
197
- }, 1200);
198
- }
199
-
200
- cell.addEventListener('click', run);
201
- cell.addEventListener('keydown', function (e) {
202
- if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); run(); }
203
- });
204
- });
205
- }
206
-
207
- /* ---------- platform filter ---------- */
208
-
209
- function initFilters() {
210
- var chips = [].slice.call(document.querySelectorAll('.chip[data-platform]'));
211
- if (!chips.length) return;
212
- var rows = [].slice.call(document.querySelectorAll('[data-platforms]'));
213
-
214
- function select(want) {
215
- chips.forEach(function (c) {
216
- c.setAttribute('aria-pressed', String(c.getAttribute('data-platform') === want));
217
- });
218
- rows.forEach(function (row) {
219
- var list = row.getAttribute('data-platforms').split(/\s+/);
220
- var show = want === 'all' || list.indexOf('all') !== -1 || list.indexOf(want) !== -1;
221
- row.hidden = !show;
222
- });
223
- /* A section whose rows are all hidden says so instead of looking broken. */
224
- [].slice.call(document.querySelectorAll('[data-filter-section]')).forEach(function (sec) {
225
- var visible = [].slice.call(sec.querySelectorAll('[data-platforms]')).some(function (r) {
226
- return !r.hidden;
227
- });
228
- sec.classList.toggle('filter-hidden', !visible);
229
- });
230
- }
231
-
232
- chips.forEach(function (c) {
233
- c.addEventListener('click', function () { select(c.getAttribute('data-platform')); });
234
- });
235
- select('all');
236
- }
237
-
238
- /* ---------- tabs ---------- */
239
-
240
- /*
241
- * One tablist per group, roving tabindex: only the selected tab is in the
242
- * tab order, arrows move between them. Panels stay in the DOM so their
243
- * commands remain copyable the moment a tab is shown.
244
- *
245
- * The markup ships every panel visible and the tablist hidden; hiding is
246
- * this function's first act. Without it — stale cache, blocked module,
247
- * file:// — the reader gets all three prompts stacked instead of controls
248
- * that do nothing.
249
- */
250
- function initTabs() {
251
- [].slice.call(document.querySelectorAll('[role="tablist"]')).forEach(function (list) {
252
- var tabs = [].slice.call(list.querySelectorAll('[role="tab"]'));
253
- if (!tabs.length) return;
254
- list.hidden = false;
255
-
256
- function select(tab, focus) {
257
- tabs.forEach(function (other) {
258
- var on = other === tab;
259
- other.setAttribute('aria-selected', String(on));
260
- other.tabIndex = on ? 0 : -1;
261
- var panel = document.getElementById(other.getAttribute('aria-controls'));
262
- if (panel) panel.hidden = !on;
263
- });
264
- if (focus) tab.focus();
265
- }
266
-
267
- tabs.forEach(function (tab, i) {
268
- tab.addEventListener('click', function () { select(tab, false); });
269
- tab.addEventListener('keydown', function (e) {
270
- var next = null;
271
- if (e.key === 'ArrowRight') next = tabs[(i + 1) % tabs.length];
272
- if (e.key === 'ArrowLeft') next = tabs[(i - 1 + tabs.length) % tabs.length];
273
- if (e.key === 'Home') next = tabs[0];
274
- if (e.key === 'End') next = tabs[tabs.length - 1];
275
- if (!next) return;
276
- e.preventDefault();
277
- select(next, true);
278
- });
279
- });
280
-
281
- var current = tabs.filter(function (t) {
282
- return t.getAttribute('aria-selected') === 'true';
283
- })[0];
284
- select(current || tabs[0], false);
285
- });
286
- }
287
-
288
- /* ---------- layer diagram ---------- */
289
-
290
- function initLayers() {
291
- var layers = [].slice.call(document.querySelectorAll('.layer[aria-controls]'));
292
- layers.forEach(function (layer) {
293
- layer.addEventListener('click', function () {
294
- var open = layer.getAttribute('aria-expanded') === 'true';
295
- layers.forEach(function (other) {
296
- other.setAttribute('aria-expanded', 'false');
297
- var d = document.getElementById(other.getAttribute('aria-controls'));
298
- if (d) d.hidden = true;
299
- });
300
- if (!open) {
301
- layer.setAttribute('aria-expanded', 'true');
302
- var detail = document.getElementById(layer.getAttribute('aria-controls'));
303
- if (detail) detail.hidden = false;
304
- }
305
- });
306
- });
307
- }
308
-
309
- function init() {
310
- initChecklist();
311
- initCopy();
312
- initCellCopy();
313
- initFilters();
314
- initTabs();
315
- initLayers();
316
- }
317
-
318
- document.addEventListener('mm-harness-content-rendered', initCopy);
319
-
320
- if (document.readyState === 'loading') {
321
- document.addEventListener('DOMContentLoaded', init);
322
- } else {
323
- init();
324
- }
325
- })();