PageSourceSearch

https://renove-station.com/wp-content/themes/renove-next/assets/js/product-list-ui.js?ver=4.7.69-1791376093

js renove-station.com collected 2026-10-08 23:01:40 UTC 6,286 bytes, 130 lines download raw bytes

1/* Same-product fallback and conservative display-only white-margin correction. */
2(function () {
3  'use strict';
4
5  function isBlank(data, offset) {
6    return data[offset + 3] <= 8 || (data[offset] >= 248 && data[offset + 1] >= 248 && data[offset + 2] >= 248);
7  }
8
9  // Keep every non-white pixel, including logos, labels and shadows. Never guess a product silhouette.
10  function contentBounds(data, width, height) {
11    var left = width, top = height, right = -1, bottom = -1;
12    for (var y = 0; y < height; y++) {
13      for (var x = 0; x < width; x++) {
14        if (!isBlank(data, (y * width + x) * 4)) {
15          left = Math.min(left, x); top = Math.min(top, y);
16          right = Math.max(right, x); bottom = Math.max(bottom, y);
17        }
18      }
19    }
20    if (right < 0) return null;
21    var pad = Math.max(3, Math.ceil(Math.max(width, height) * 0.035));
22    left = Math.max(0, left - pad); top = Math.max(0, top - pad);
23    right = Math.min(width - 1, right + pad); bottom = Math.min(height - 1, bottom + pad);
24    if (left === 0 && top === 0 && right === width - 1 && bottom === height - 1) return null;
25    return { x: left / width, y: top / height, w: (right + 1 - left) / width, h: (bottom + 1 - top) / height };
26  }
27
28  function fitBounds(bounds, naturalWidth, naturalHeight, frameWidth, frameHeight) {
29    if (!bounds || !naturalWidth || !naturalHeight || frameWidth <= 20 || frameHeight <= 20) return null;
30    var availableWidth = frameWidth - 20, availableHeight = frameHeight - 20;
31    var baseScale = Math.min(availableWidth / naturalWidth, availableHeight / naturalHeight);
32    var scale = Math.min(availableWidth / (naturalWidth * bounds.w), availableHeight / (naturalHeight * bounds.h), baseScale * 3);
33    var w = naturalWidth * scale, h = naturalHeight * scale;
34    return { width: w, height: h, left: (frameWidth - w * bounds.w) / 2 - w * bounds.x, top: (frameHeight - h * bounds.h) / 2 - h * bounds.y };
35  }
36
37  // Pure helpers are exported for local algorithm checks, never added to browser globals.
38  if (typeof module !== 'undefined' && module.exports) module.exports = { contentBounds: contentBounds, fitBounds: fitBounds };
39  if (typeof document === 'undefined') return;
40
41  var samples = new Map();
42  function sampleImage(img) {
43    var key = img.currentSrc || img.src;
44    if (samples.has(key)) return samples.get(key);
45    var result = null;
46    try {
47      var ratio = Math.min(1, 420 / Math.max(img.naturalWidth, img.naturalHeight));
48      var canvas = document.createElement('canvas');
49      canvas.width = Math.max(1, Math.round(img.naturalWidth * ratio));
50      canvas.height = Math.max(1, Math.round(img.naturalHeight * ratio));
51      var ctx = canvas.getContext('2d', { willReadFrequently: true });
52      if (ctx) {
53        ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
54        result = contentBounds(ctx.getImageData(0, 0, canvas.width, canvas.height).data, canvas.width, canvas.height);
55      }
56    } catch (error) {
57      // CORS/offloaded assets: leave the ordinary centered contain display intact.
58      result = null;
59    }
60    samples.set(key, result);
61    return result;
62  }
63
64  function initializeMedia(frame) {
65    var img = frame.querySelector('img'), status = frame.querySelector('.rn-product-image-status');
66    if (!img) return;
67    var candidates = [];
68    try { candidates = JSON.parse(img.getAttribute('data-rn-image-candidates') || '[]'); } catch (error) { candidates = []; }
69    if (!Array.isArray(candidates)) candidates = [];
70    var index = 0, bounds = null;
71    function clearPosition() {
72      ['width','height','left','top','right','bottom','position','padding','transform','object-fit'].forEach(function (key) { img.style.removeProperty(key); });
73    }
74    function position() {
75      if (img.hidden || !bounds) return;
76      var fit = fitBounds(bounds, img.naturalWidth, img.naturalHeight, frame.clientWidth, frame.clientHeight);
77      if (!fit) return;
78      img.style.setProperty('position', 'absolute', 'important');
79      img.style.setProperty('right', 'auto', 'important');
80      img.style.setProperty('bottom', 'auto', 'important');
81      img.style.setProperty('padding', '0', 'important');
82      img.style.setProperty('transform', 'none', 'important');
83      img.style.setProperty('object-fit', 'contain', 'important');
84      Object.keys(fit).forEach(function (key) { img.style.setProperty(key, fit[key] + 'px', 'important'); });
85    }
86    function loaded() {
87      if (!img.naturalWidth) { failed(); return; }
88      img.hidden = false;
89      if (status) status.hidden = true;
90      frame.setAttribute('data-rn-image-state', 'loaded');
91      if (frame.hasAttribute('data-rn-normalize-image')) {
92        bounds = sampleImage(img);
93        position();
94        frame.setAttribute('data-rn-margin-state', bounds ? 'adjusted' : 'contain');
95      }
96    }
97    function failed() {
98      clearPosition(); bounds = null;
99      index++;
100      if (index < candidates.length) { img.src = candidates[index]; return; }
101      img.hidden = true;
102      if (status) status.hidden = false;
103      frame.setAttribute('data-rn-image-state', 'missing');
104    }
105    img.addEventListener('load', loaded);
106    img.addEventListener('error', failed);
107    if (frame.hasAttribute('data-rn-normalize-image')) {
108      if (typeof ResizeObserver !== 'undefined') new ResizeObserver(position).observe(frame);
109      else window.addEventListener('resize', position);
110    }
111    if (img.complete) { if (img.naturalWidth) loaded(); else failed(); }
112  }
113
114  function initializeFilter(details) {
115    var media = window.matchMedia('(max-width: 760px)');
116    var mobileOpen = details.getAttribute('data-rn-active-filters') === '1';
117    function apply() { details.open = media.matches ? mobileOpen : true; }
118    details.addEventListener('toggle', function () { if (media.matches) mobileOpen = details.open; });
119    if (media.addEventListener) media.addEventListener('change', apply);
120    else media.addListener(apply);
121    apply();
122  }
123
124  function start() {
125    document.querySelectorAll('[data-rn-product-media]').forEach(initializeMedia);
126    document.querySelectorAll('[data-rn-filter-disclosure]').forEach(initializeFilter);
127  }
128  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start);
129  else start();
130})();

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.