Oregami
Repositories/oxedyne/daimond

oxedyne/daimond/ext/announce.js

2.4 KiB, 1 run

created by r2519314175:867, which is this file's identity for as long as the history lasts, whatever it is later renamed to

download · who wrote it · its history

1// Runs only on the Daimond origins. It does two small things.
2//
3// One: it lets the page discover the extension without hard-coding an id, by
4// stamping the id on <html>. The page then talks to the broker with
5// chrome.runtime.sendMessage(id, msg).
6//
7// Two: it carries the language the user chose in the app across to the
8// extension, which has no other way to learn it. Chrome would dress the grant
9// window in the BROWSER's UI language -- and a person reading a Japanese app is
10// not necessarily running a Japanese Chrome. The one place the extension asks
11// the user to trust it is the worst place in the product to change language.
12//
13// It reads one key of the app's own storage. It sends nothing anywhere else.
14
15'use strict';
16
17(() => {
18
19 const id = chrome.runtime.id;
20 const root = document.documentElement;
21
22 // Stamp for a page that is already parsed, and for one that is not.
23 root.dataset.daimondHands = id;
24 root.dataset.daimondHandsVer = chrome.runtime.getManifest().version;
25
26 // The page may have been listening before we ran.
27 window.dispatchEvent(new CustomEvent('daimond-hands', {
28 detail: { id, version: chrome.runtime.getManifest().version },
29 }));
30
31 // ── The language the app is speaking ────────────────────────────────
32
33 /// Where the app keeps the chosen language. Empty means the user has not
34 /// chosen one, and the browser's own language is the honest answer.
35 const LS = 'daimond-locale';
36 let last = null;
37
38 function mirror() {
39 let code = '';
40 try {
41 code = localStorage.getItem(LS) || '';
42 } catch (e) {
43 return; // Private mode. Whatever was mirrored before stands.
44 }
45 if (code === last) return;
46 last = code;
47 try { chrome.storage.local.set({ locale: code }); } catch (e) { /* worker asleep */ }
48 }
49
50 mirror();
51
52 // The app writes the language to storage and then stamps it on <html>, so
53 // the attribute is the signal that a choice has just been made -- and it
54 // arrives whether the change came from the picker, a sync, or a reload.
55 try {
56 new MutationObserver(mirror).observe(root, { attributes: true, attributeFilter: ['lang'] });
57 } catch (e) { /* no observer, no live updates; the load-time read stands */ }
58
59 // A change made in another tab reaches this one as a storage event.
60 window.addEventListener('storage', (ev) => { if (!ev.key || ev.key === LS) mirror(); });
61
62})();