PageSourceSearch

https://pupwife.com/scripts/desktop/citrusKitTvSecret.js

js pupwife.com collected 2026-09-30 15:04:59 UTC 4,840 bytes, 161 lines download raw bytes

1/**
2 * Secret KitTV window — triple-click the taskbar clock, or hold the Start logo ~3s.
3 */
4(function (global) {
5    'use strict';
6
7    var AUX_ID = 'kittv';
8    var KITTV_URL = 'https://wowee.neocities.org/kittv/kittv';
9    var CONTENT_W = 640;
10    var CONTENT_H = 480;
11    var TITLEBAR_PX = 30;
12    var HOLD_MS = 3000;
13    var TRIPLE_CLICK_MS = 600;
14
15    var holdTimer = null;
16    var holdTriggered = false;
17    var clockClickCount = 0;
18    var clockClickTimer = null;
19
20    function qs(sel) {
21        return document.querySelector(sel);
22    }
23
24    function isCitrusDesktop() {
25        return document.body && document.body.classList.contains('page-citrusos');
26    }
27
28    function getUiScale() {
29        try {
30            var raw = getComputedStyle(document.documentElement).getPropertyValue('--citrusos-ui-scale');
31            var scale = parseFloat(raw);
32            return scale > 0 ? scale : 1;
33        } catch (e) {
34            return 1;
35        }
36    }
37
38    function getShellSize() {
39        var titlebarH = Math.round(TITLEBAR_PX * getUiScale());
40        return {
41            w: CONTENT_W,
42            h: CONTENT_H + titlebarH
43        };
44    }
45
46    function centerPosition(shellW, shellH) {
47        return {
48            x: Math.max(8, Math.round((global.innerWidth - shellW) / 2)),
49            y: Math.max(8, Math.round((global.innerHeight - shellH - 48) / 2))
50        };
51    }
52
53    function openKitTv() {
54        var desktop = global.CitrusDesktop;
55        if (!desktop || typeof desktop.openAuxWindow !== 'function') return;
56
57        var shell = getShellSize();
58        var pos = centerPosition(shell.w, shell.h);
59        desktop.openAuxWindow({
60            id: AUX_ID,
61            label: 'Signal Lost\u2026',
62            icon: 'fa-solid fa-tv',
63            w: shell.w,
64            h: shell.h,
65            x: pos.x,
66            y: pos.y,
67            nearChat: false,
68            resizable: false,
69            auxClass: 'citrus-window--fixed-size citrus-window--kittv',
70            onMount: function (contentEl) {
71                contentEl.classList.add('citrus-window__content--iframe', 'citrusos-app-active');
72                var iframe = document.createElement('iframe');
73                iframe.className = 'citrus-window__iframe';
74                iframe.title = 'KitTV';
75                iframe.src = KITTV_URL;
76                iframe.setAttribute('referrerpolicy', 'no-referrer-when-downgrade');
77                iframe.setAttribute('allow', 'fullscreen');
78                iframe.setAttribute('allowfullscreen', '');
79                contentEl.appendChild(iframe);
80            }
81        });
82    }
83
84    function clearHoldTimer() {
85        if (holdTimer) {
86            clearTimeout(holdTimer);
87            holdTimer = null;
88        }
89    }
90
91    function onStartLogoPointerDown() {
92        clearHoldTimer();
93        holdTriggered = false;
94        holdTimer = setTimeout(function () {
95            holdTimer = null;
96            holdTriggered = true;
97            openKitTv();
98        }, HOLD_MS);
99    }
100
101    function onStartLogoPointerEnd() {
102        clearHoldTimer();
103    }
104
105    function onStartBtnClick(ev) {
106        if (!holdTriggered) return;
107        ev.preventDefault();
108        ev.stopPropagation();
109        if (typeof ev.stopImmediatePropagation === 'function') {
110            ev.stopImmediatePropagation();
111        }
112        holdTriggered = false;
113    }
114
115    function onClockClick() {
116        clockClickCount += 1;
117        if (clockClickTimer) clearTimeout(clockClickTimer);
118        if (clockClickCount >= 3) {
119            clockClickCount = 0;
120            clockClickTimer = null;
121            openKitTv();
122            return;
123        }
124        clockClickTimer = setTimeout(function () {
125            clockClickCount = 0;
126            clockClickTimer = null;
127        }, TRIPLE_CLICK_MS);
128    }
129
130    function bindTriggers() {
131        var startLogo = qs('.citrusos-start-btn__logo');
132        var startBtn = qs('#citrusos-start-btn');
133        var clockTray = qs('.citrus-tray-clock');
134
135        if (startLogo) {
136            startLogo.addEventListener('pointerdown', onStartLogoPointerDown);
137            startLogo.addEventListener('pointerup', onStartLogoPointerEnd);
138            startLogo.addEventListener('pointercancel', onStartLogoPointerEnd);
139            startLogo.addEventListener('pointerleave', onStartLogoPointerEnd);
140        }
141
142        if (startBtn) {
143            startBtn.addEventListener('click', onStartBtnClick, true);
144        }
145
146        if (clockTray) {
147            clockTray.addEventListener('click', onClockClick);
148        }
149    }
150
151    function init() {
152        if (!isCitrusDesktop()) return;
153        bindTriggers();
154    }
155
156    if (document.readyState === 'loading') {
157        document.addEventListener('DOMContentLoaded', init);
158    } else {
159        init();
160    }
161})(typeof window !== 'undefined' ? window : this);

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.