PageSourceSearch

https://ballotbox.scot/wp-content/plugins/social-integration-for-b…luesky-profile-banner-gradient.js?ver=2.2.1

js ballotbox.scot collected 2026-10-02 06:35:14 UTC 5,196 bytes, 142 lines download raw bytes

1(function() {
2    'use strict';
3
4    /**
5     * Adjust RGB color brightness by a percentage
6     * @param {number} r - Red value (0-255)
7     * @param {number} g - Green value (0-255)
8     * @param {number} b - Blue value (0-255)
9     * @param {number} percent - Percentage to brighten (positive) or darken (negative)
10     * @returns {Array} - Adjusted [r, g, b] values
11     */
12    function adjustBrightness(r, g, b, percent) {
13        var amount = Math.round(2.55 * percent);
14        return [
15            Math.min(255, Math.max(0, r + amount)),
16            Math.min(255, Math.max(0, g + amount)),
17            Math.min(255, Math.max(0, b + amount))
18        ];
19    }
20
21    /**
22     * Generate deterministic RGB colors from a string (avatar URL)
23     * Used as fallback when CORS blocks Color Thief extraction
24     * @param {string} str - String to hash (avatar URL)
25     * @returns {Array} - [r, g, b] values
26     */
27    function hashStringToRGB(str) {
28        var hash = 0;
29        for (var i = 0; i < str.length; i++) {
30            hash = str.charCodeAt(i) + ((hash << 5) - hash);
31            hash = hash & hash; // Convert to 32-bit integer
32        }
33
34        // Generate colors with reasonable saturation and brightness
35        var r = (hash & 0xFF0000) >> 16;
36        var g = (hash & 0x00FF00) >> 8;
37        var b = hash & 0x0000FF;
38
39        // Ensure colors aren't too dark (minimum brightness)
40        r = Math.max(60, r);
41        g = Math.max(60, g);
42        b = Math.max(60, b);
43
44        return [r, g, b];
45    }
46
47    /**
48     * Apply gradient to banner element
49     * @param {HTMLElement} element - Banner element with data-avatar-url
50     */
51    function applyGradientFallback(element) {
52        var avatarUrl = element.getAttribute('data-avatar-url');
53        if (!avatarUrl) {
54            element.classList.remove('bluesky-banner-gradient-pending');
55            return;
56        }
57
58        // Check if ColorThief is available
59        if (typeof ColorThief === 'undefined') {
60            console.warn('ColorThief library not loaded, using hash-based gradient fallback');
61            applyHashGradient(element, avatarUrl);
62            return;
63        }
64
65        // Create offscreen image for color extraction
66        var img = new Image();
67        img.crossOrigin = 'Anonymous'; // Required for Color Thief canvas access
68
69        img.onload = function() {
70            try {
71                var colorThief = new ColorThief();
72                var dominantColor = colorThief.getColor(img);
73
74                if (dominantColor && dominantColor.length === 3) {
75                    var r = dominantColor[0];
76                    var g = dominantColor[1];
77                    var b = dominantColor[2];
78
79                    // Create gradient with brightened second color
80                    var brightened = adjustBrightness(r, g, b, 20);
81                    var gradient = 'linear-gradient(135deg, rgb(' + r + ',' + g + ',' + b + '), rgb(' + brightened[0] + ',' + brightened[1] + ',' + brightened[2] + '))';
82
83                    element.style.setProperty('--bluesky-banner-gradient', gradient);
84                    element.classList.remove('bluesky-banner-gradient-pending');
85                } else {
86                    // Color extraction failed, use hash fallback
87                    applyHashGradient(element, avatarUrl);
88                }
89            } catch (error) {
90                console.warn('Color Thief extraction failed, using hash-based gradient:', error);
91                applyHashGradient(element, avatarUrl);
92            }
93        };
94
95        img.onerror = function() {
96            // CORS error or network failure, use hash-based gradient
97            console.warn('Image load failed (likely CORS), using hash-based gradient');
98            applyHashGradient(element, avatarUrl);
99        };
100
101        img.src = avatarUrl;
102    }
103
104    /**
105     * Apply hash-based gradient when Color Thief unavailable or fails
106     * @param {HTMLElement} element - Banner element
107     * @param {string} avatarUrl - Avatar URL to hash
108     */
109    function applyHashGradient(element, avatarUrl) {
110        var color1 = hashStringToRGB(avatarUrl);
111        var color2 = hashStringToRGB(avatarUrl + '_alt'); // Different hash for second color
112
113        var gradient = 'linear-gradient(135deg, rgb(' + color1[0] + ',' + color1[1] + ',' + color1[2] + '), rgb(' + color2[0] + ',' + color2[1] + ',' + color2[2] + '))';
114
115        element.style.setProperty('--bluesky-banner-gradient', gradient);
116        element.classList.remove('bluesky-banner-gradient-pending');
117    }
118
119    /**
120     * Initialize gradient fallback on DOMContentLoaded
121     */
122    function init() {
123        var pendingElements = document.querySelectorAll('.bluesky-banner-gradient-pending');
124
125        if (pendingElements.length === 0) {
126            return;
127        }
128
129        // Process each banner element
130        for (var i = 0; i < pendingElements.length; i++) {
131            applyGradientFallback(pendingElements[i]);
132        }
133    }
134
135    // Run on DOMContentLoaded
136    if (document.readyState === 'loading') {
137        document.addEventListener('DOMContentLoaded', init);
138    } else {
139        // DOM already loaded
140        init();
141    }
142})();

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.