PageSourceSearch

https://finstar.hk/js/image-acceleration.js

js finstar.hk collected 2026-10-02 01:02:05 UTC 5,260 bytes, 199 lines download raw bytes

1(function (window, document) {
2  "use strict";
3
4  var runtimeConfig = window.FINSTAR_IMAGE_ACCELERATION || {};
5  var hostname = (window.location && window.location.hostname) || "";
6  var isLocalHost =
7    hostname === "localhost" ||
8    hostname === "127.0.0.1" ||
9    hostname === "::1" ||
10    /\.local$/.test(hostname);
11  var isPagesPreview = /\.pages\.dev$/i.test(hostname);
12
13  var config = {
14    enabled: runtimeConfig.enabled !== false,
15    provider: runtimeConfig.provider || "cloudflare-cgi",
16    quality: Number(runtimeConfig.quality) || 76,
17    defaultWidth: Number(runtimeConfig.defaultWidth) || 1400,
18    avatarWidth: Number(runtimeConfig.avatarWidth) || 240,
19    newsWidth: Number(runtimeConfig.newsWidth) || 1400,
20    heroWidth: Number(runtimeConfig.heroWidth) || 1920,
21  };
22
23  function isSameOriginUrl(src) {
24    try {
25      var parsed = new URL(src, window.location.href);
26      return parsed.origin === window.location.origin;
27    } catch (error) {
28      return false;
29    }
30  }
31
32  function normalizePath(src) {
33    if (!src) {
34      return "";
35    }
36
37    if (/^(data:|blob:|mailto:|javascript:)/i.test(src)) {
38      return "";
39    }
40
41    if (/^https?:\/\//i.test(src) || /^\/\//.test(src)) {
42      if (!isSameOriginUrl(src)) {
43        return "";
44      }
45
46      try {
47        var absolute = new URL(src, window.location.href);
48        src = absolute.pathname;
49      } catch (error) {
50        return "";
51      }
52    }
53
54    src = src.replace(/^\.\//, "").replace(/^\/+/, "");
55    if (!/^(images|profilepics)\//.test(src)) {
56      return "";
57    }
58
59    return src;
60  }
61
62  function shouldUseCloudflareCgi() {
63    return (
64      config.enabled &&
65      config.provider === "cloudflare-cgi" &&
66      !isLocalHost &&
67      !isPagesPreview
68    );
69  }
70
71  function defaultWidthByKind(kind) {
72    if (kind === "avatar") {
73      return config.avatarWidth;
74    }
75    if (kind === "hero") {
76      return config.heroWidth;
77    }
78    if (kind === "news") {
79      return config.newsWidth;
80    }
81    return config.defaultWidth;
82  }
83
84  function buildCloudflareCgiUrl(src, options) {
85    var normalizedPath = normalizePath(src);
86    if (!normalizedPath) {
87      return src;
88    }
89
90    var opts = options || {};
91    var requestedFormat = String(opts.format || "auto").toLowerCase();
92    var format = /^(auto|avif|webp|jpeg|png|json)$/.test(requestedFormat)
93      ? requestedFormat
94      : "auto";
95    var quality = Number(opts.quality) || config.quality;
96    var width = Number(opts.width) || defaultWidthByKind(opts.kind);
97    var directives = ["format=" + format, "metadata=none", "quality=" + quality];
98
99    if (width > 0) {
100      directives.push("width=" + width, "fit=scale-down");
101    }
102
103    return "/cdn-cgi/image/" + directives.join(",") + "/" + normalizedPath;
104  }
105
106  function getTargetWidth(img, kind) {
107    var explicit = Number(img.getAttribute("data-cf-width"));
108    if (explicit > 0) {
109      return explicit;
110    }
111
112    var attrWidth = Number(img.getAttribute("width"));
113    if (attrWidth > 0) {
114      return Math.min(Math.round(attrWidth * 2), 2000);
115    }
116
117    return defaultWidthByKind(kind);
118  }
119
120  function bindFallback(img, originalSrc) {
121    if (img.getAttribute("data-cf-fallback-bound") === "1") {
122      return;
123    }
124
125    img.setAttribute("data-cf-fallback-bound", "1");
126    img.addEventListener(
127      "error",
128      function () {
129        if (img.getAttribute("src") !== originalSrc) {
130          img.setAttribute("src", originalSrc);
131        }
132      },
133      { once: true }
134    );
135  }
136
137  function optimizeImageElement(img, options) {
138    if (!img) {
139      return;
140    }
141
142    var opts = options || {};
143    var kind = opts.kind || "default";
144    var keepEager = opts.keepEager === true || img.getAttribute("fetchpriority") === "high";
145
146    if (!img.hasAttribute("decoding")) {
147      img.setAttribute("decoding", "async");
148    }
149    if (!keepEager && !img.hasAttribute("loading")) {
150      img.setAttribute("loading", "lazy");
151    }
152
153    var src = img.getAttribute("src");
154    if (!src || !shouldUseCloudflareCgi()) {
155      return;
156    }
157
158    var optimizedSrc = buildCloudflareCgiUrl(src, {
159      kind: kind,
160      width: opts.width || getTargetWidth(img, kind),
161      quality: opts.quality,
162    });
163
164    if (optimizedSrc === src) {
165      return;
166    }
167
168    if (!img.getAttribute("data-origin-src")) {
169      img.setAttribute("data-origin-src", src);
170    }
171    bindFallback(img, src);
172    img.setAttribute("src", optimizedSrc);
173  }
174
175  function optimizeNonSlideImages() {
176    var images = document.querySelectorAll("img:not(.mySlides)");
177    Array.prototype.forEach.call(images, function (img) {
178      var src = img.getAttribute("src") || "";
179      var kind = src.indexOf("profilepics/") !== -1 ? "avatar" : "default";
180      optimizeImageElement(img, { kind: kind });
181    });
182  }
183
184  window.finstarImageUrl = function (src, options) {
185    if (!shouldUseCloudflareCgi()) {
186      return src;
187    }
188    return buildCloudflareCgiUrl(src, options);
189  };
190
191  window.finstarOptimizeImageElement = optimizeImageElement;
192  window.finstarBindImageFallback = bindFallback;
193
194  if (document.readyState === "loading") {
195    document.addEventListener("DOMContentLoaded", optimizeNonSlideImages);
196  } else {
197    optimizeNonSlideImages();
198  }
199})(window, document);

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.