1/** 2 * card-accent.js â color AUTOMÃTICO: extrae el tono dominante de la portada y 3 * tematiza el cuerpo de la tarjeta (variables --accent/--accent-text + clase 4 * .news-card--themed, cuyo estilo vive en news-accent.css). 5 * Salta las tarjetas con color manual (ya tematizadas por el servidor). 6 * Maneja CORS: si getImageData falla, reintenta con crossOrigin='anonymous'. 7 * Mismo origen, sin dependencias. 8 */ 9(function () { 10 'use strict'; 11 12 function sample(img) { 13 var w = 20, h = 20; 14 var c = document.createElement('canvas'); 15 c.width = w; c.height = h; 16 var ctx = c.getContext('2d'); 17 try { 18 ctx.drawImage(img, 0, 0, w, h); 19 var d = ctx.getImageData(0, 0, w, h).data; 20 var r = 0, g = 0, b = 0, n = 0; 21 for (var i = 0; i < d.length; i += 4) { 22 if (d[i + 3] < 125) continue; 23 var mx = Math.max(d[i], d[i + 1], d[i + 2]); 24 var mn = Math.min(d[i], d[i + 1], d[i + 2]); 25 if (mx > 244 && mn > 244) continue; // casi-blanco 26 if (mx < 12) continue; // casi-negro 27 r += d[i]; g += d[i + 1]; b += d[i + 2]; n++; 28 } 29 if (!n) return null; 30 return [Math.round(r / n), Math.round(g / n), Math.round(b / n)]; 31 } catch (e) { 32 return null; // CORS o canvas tainted 33 } 34 } 35 36 function apply(card, rgb) { 37 var lum = 0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2]; 38 card.style.setProperty('--accent', 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')'); 39 card.style.setProperty('--accent-text', lum > 150 ? '#1a1208' : '#ffffff'); 40 card.style.setProperty('--accent-shadow', 'rgba(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ',.5)'); 41 card.classList.add('news-card--themed'); 42 } 43 44 /** 45 * Intenta samplear la imagen. Si falla (CORS), recarga con crossOrigin. 46 */ 47 function tryApply(card, img) { 48 var rgb = sample(img); 49 if (rgb) { apply(card, rgb); return; } 50 51 // Reintento con crossOrigin='anonymous' (una sola vez) 52 if (img.dataset.accentRetried) return; 53 img.dataset.accentRetried = '1'; 54 var clone = new Image(); 55 clone.crossOrigin = 'anonymous'; 56 clone.onload = function () { 57 var rgb2 = sample(clone); 58 if (rgb2) apply(card, rgb2); 59 }; 60 // Añadir un cache-buster mÃnimo si la URL no tiene query 61 clone.src = img.src; 62 } 63 64 function run() { 65 document.querySelectorAll('.news-card').forEach(function (card) { 66 // El servidor ya tematizó las de color manual. 67 if (card.getAttribute('data-accent') === 'manual' || card.classList.contains('news-card--themed')) return; 68 var img = card.querySelector('img.news-card-img-bg'); 69 if (!img) return; 70 var go = function () { tryApply(card, img); }; 71 if (img.complete && img.naturalWidth) go(); 72 else img.addEventListener('load', go); 73 }); 74 } 75 76 if (document.readyState !== 'loading') run(); 77 else document.addEventListener('DOMContentLoaded', run); 78})(); 79
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.