PageSourceSearch

https://blockstream.com/assets/js/utility-scripts/detect-device-os-universal.js

js blockstream.com collected 2026-10-01 08:39:15 UTC 6,080 bytes, 148 lines download raw bytes

1// assets/js/utility-scripts/detect-device-os-universal.js
2
3(function() {
4    async function initGreenDownload() {
5        let platform, os, architecture;
6
7        try {
8            let userData = await navigator.userAgentData.getHighEntropyValues(["architecture"]);
9            platform = userData.platform;
10            architecture = userData.architecture;
11        } catch(e) {
12            platform = window.navigator?.userAgentData?.platform || window.navigator.platform;
13        }
14
15        var userAgent = window.navigator.userAgent,
16            macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K', 'macOS'],
17            windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
18            iosPlatforms = ['iPhone', 'iPad', 'iPod'];
19
20        if (macosPlatforms.indexOf(platform) !== -1) {
21            if (architecture == "x86")
22                os = 'Mac_x86';
23            else if (architecture == "arm")
24                os = 'Mac_ARM';
25            else
26                os = 'Mac';
27        } else if (iosPlatforms.indexOf(platform) !== -1) {
28            os = 'iOS';
29        } else if (windowsPlatforms.indexOf(platform) !== -1) {
30            os = 'Windows';
31        } else if (/Android/.test(userAgent)) {
32            os = 'Android';
33        } else if (/Linux/.test(platform)) {
34            os = 'Linux';
35        }
36
37        // Process all green download components on the page
38        const greenDownloadComponents = document.querySelectorAll('[data-green-download]');
39        
40        greenDownloadComponents.forEach(component => {
41            const dropdownTrigger = component.querySelector('[data-role="dropdown-trigger"]');
42            const macX86Button = component.querySelector('[data-role="mac_x86"]');
43            const macArmButton = component.querySelector('[data-role="mac_arm"]');
44            const iosButton = component.querySelector('[data-role="ios"]');
45            const windowsButton = component.querySelector('[data-role="windows"]');
46            const androidDropdown = component.querySelector('[data-role="android"]');
47            const linuxDropdown = component.querySelector('[data-role="linux"]');
48            const allDropdown = component.querySelector('[data-role="all"]');
49
50            // Hide dropdown trigger by default
51            if (dropdownTrigger) dropdownTrigger.style.display = "none";
52
53            switch (os) {
54                case "Mac_x86":
55                    if (macX86Button) macX86Button.style.display = "flex";
56                    break;
57                case "Mac_ARM":
58                    if (macArmButton) macArmButton.style.display = "flex";
59                    break;
60                case "Mac":
61                    if (macX86Button) macX86Button.style.display = "flex";
62                    break;
63                case "iOS":
64                    if (iosButton) iosButton.style.display = "flex";
65                    break;
66                case "Windows":
67                    if (windowsButton) windowsButton.style.display = "flex";
68                    break;
69                case "Android":
70                    if (androidDropdown) androidDropdown.style.display = "flex";
71                    break;
72                case "Linux":
73                    if (linuxDropdown) linuxDropdown.style.display = "flex";
74                    break;
75                default:
76                    if (allDropdown) allDropdown.style.display = "flex";
77            }
78        });
79
80        // Set up click prevention for all dropdown triggers
81        const allDropdownTriggers = document.querySelectorAll('[data-role="dropdown-trigger"], .dropdown-trigger');
82        allDropdownTriggers.forEach(trigger => {
83            trigger.addEventListener("click", function(e) {
84                e.preventDefault();
85            });
86        });
87
88        // Set up pixel tracking
89        const downloadButtons = document.querySelectorAll('.greenDownload .dropdown-item, .greenDownload .green-download-button, .greenDownload .green-mac-download');
90        downloadButtons.forEach(button => button.addEventListener("click", pixelTrigger));
91    }
92
93    let pixelTriggered = false;
94    function pixelTrigger(e) {
95        if (!pixelTriggered) {
96            pixelTriggered = true;
97            let platform = e.target.closest('[data-green-download]')?.getAttribute('data-green-download') || 'unknown';
98
99            // X pixel
100            if (typeof twq !== 'undefined') {
101                twq('event', 'tw-ondrb-ondrc', {
102                    contents: [{
103                        content_type: 'green download',
104                        content_id: null,
105                        content_name: 'green download',
106                        content_price: null,
107                        num_items: 1,
108                        content_group_id: null
109                    }],
110                    platform: platform,
111                });
112            }
113
114            // Reddit pixel
115            if (typeof rdt !== 'undefined') {
116                rdt('track', 'Custom', {
117                    customEventName: 'Green download',
118                });
119            }
120        }
121    }
122
123    function showAllDownloadOptions(componentSelector) {
124        const component = document.querySelector(componentSelector || '[data-green-download]');
125        if (!component) return;
126
127        // Hide all platform-specific elements
128        const elementsToHide = ['mac', 'mac_x86', 'mac_arm', 'ios', 'windows', 'android', 'linux'];
129        elementsToHide.forEach(role => {
130            const element = component.querySelector(`[data-role="${role}"]`);
131            if (element) element.style.display = "none";
132        });
133
134        // Show all options
135        const allDropdown = component.querySelector('[data-role="all"]');
136        if (allDropdown) allDropdown.style.display = "flex";
137    }
138
139    // Make the function globally available
140    window.showAllDownloadOptions = showAllDownloadOptions;
141
142    // Initialize when DOM is ready
143    if (document.readyState === 'loading') {
144        document.addEventListener('DOMContentLoaded', initGreenDownload);
145    } else {
146        initGreenDownload();
147    }
148})();

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.