PageSourceSearch

https://fortune-cookie.tokyo/assets/js/dark-mode-auto-trigger.js?v=1.0.610

js fortune-cookie.tokyo collected 2026-10-07 17:57:57 UTC 4,391 bytes, 110 lines download raw bytes

1/**
2 * 争奪戦 ダークモード 自動トリガー(全ページ共通)
3 *
4 * window.AUTO_DARK_BATTLE が DarkModeBattleComposer から注入されている場合のみ動作する。
5 *
6 *   window.AUTO_DARK_BATTLE = {
7 *       lotteryId: number,
8 *       startMs:  number,  // 開催開始時刻 (ms epoch)
9 *       endMs:    number,  // 開催終了時刻 (ms epoch)
10 *   };
11 *
12 * 仕様:
13 *   - 対象ページ (body.page-top / body.page-battle-lottery / body.page-lottery / body.page-coin-conversion) のみダーク化
14 *   - page-battle-lottery は常時ダークのため turnOff しない
15 *   - 開催 10 秒前 (= floor((startMs - now)/1000) <= 10) で ON
16 *   - 開催終了 / 30 分経過 で OFF(フェイルセーフ)
17 *   - 売り切れ即時 OFF は lottery_page 側の MutationObserver が担当
18 *   - is-active-dark-battle クラスを該当 lottery_id を持つ要素に付与(虹色ボーダー用)
19 */
20(function () {
21    var battle = window.AUTO_DARK_BATTLE;
22    if (!battle || typeof battle.startMs !== 'number' || typeof battle.endMs !== 'number') {
23        return;
24    }
25
26    var DARK_DISPLAY_SEC = 10;
27    var DARK_MAX_MS = 30 * 60 * 1000;
28    var html = document.documentElement;
29    var darkOffTimer = null;
30
31    function isTargetPage() {
32        var body = document.body;
33        if (!body) return false;
34        return body.classList.contains('page-top')
35            || body.classList.contains('page-battle-lottery')
36            || body.classList.contains('page-lottery')
37            || body.classList.contains('page-coin-conversion');
38    }
39
40    function isPermanentDarkPage() {
41        var body = document.body;
42        return body && body.classList.contains('page-battle-lottery');
43    }
44
45    function turnOn() {
46        if (!isTargetPage()) return;
47        if (html.classList.contains('dark-mode-on')) return;
48        html.classList.add('dark-mode-on');
49        if (isPermanentDarkPage()) return;
50        if (darkOffTimer) clearTimeout(darkOffTimer);
51        darkOffTimer = setTimeout(turnOff, DARK_MAX_MS);
52    }
53
54    function turnOff() {
55        // battle 系ダークトリガーが管轄する対象ページ以外では剥奪しない.
56        // 例: page-auction は auction-room.js が独立で dark-mode-on を管理するため、
57        // battle 終了時にここで剥奪すると意図せずライトモードに戻ってしまう.
58        // docs/features/auction-dark-mode-low-remaining/spec.md 参照
59        if (!isTargetPage()) return;
60        if (isPermanentDarkPage()) return;
61        html.classList.remove('dark-mode-on');
62        if (darkOffTimer) { clearTimeout(darkOffTimer); darkOffTimer = null; }
63    }
64
65    function whenBodyReady(fn) {
66        if (document.body) { fn(); return; }
67        document.addEventListener('DOMContentLoaded', fn, { once: true });
68    }
69
70    // 開催中の battle に対応する DOM 要素(カード / サムネ / カレンダー)に
71    // is-active-dark-battle クラスを付与する。CSS 側で「現在開催中の battle のみ」に
72    // 虹色ボーダーを当てるためのマーカー。
73    function markActiveBattleNodes() {
74        var sel = '[data-lottery-id="' + battle.lotteryId + '"]';
75        document.querySelectorAll(sel).forEach(function (el) {
76            el.classList.add('is-active-dark-battle');
77        });
78    }
79    whenBodyReady(markActiveBattleNodes);
80
81    function shouldBeDark(t) {
82        if (t >= battle.startMs) return true;
83        var displaySec = Math.floor((battle.startMs - t) / 1000);
84        return displaySec <= DARK_DISPLAY_SEC;
85    }
86
87    var now = Date.now();
88    if (battle.endMs && now >= battle.endMs) return; // 既に終了
89
90    if (shouldBeDark(now)) {
91        whenBodyReady(turnOn);
92    }
93
94    if (battle.endMs) {
95        setTimeout(turnOff, Math.max(0, battle.endMs - now));
96    }
97
98    // CountdownSyncClock に subscribe して、カウントダウン表示と同フレームでダーク化判定
99    if (window.CountdownSyncClock) {
100        var darkTick = window.CountdownSyncClock.subscribe(function (t) {
101            if (battle.endMs && t >= battle.endMs) {
102                window.CountdownSyncClock.unsubscribe(darkTick);
103                return;
104            }
105            if (shouldBeDark(t) && !html.classList.contains('dark-mode-on')) {
106                whenBodyReady(turnOn);
107            }
108        });
109    }
110})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.