1(function () { 2 "use strict"; 3 4 var rightNowContainer = document.getElementById("reviewTrendingList"); 5 var artistContainer = document.getElementById("trendingArtistList"); 6 var freeShippingContainer = document.getElementById("freeShippingProducts"); 7 var freeShippingSection = document.getElementById("free"); 8 var newsContainer = document.querySelector('#news > ul'); 9 10 if (!rightNowContainer && !artistContainer && !freeShippingContainer && !newsContainer) return; 11 12 var MAX_ITEMS = 12; 13 var JSON_PATH = "assets/data/trending.json"; 14 var JSON_CACHE_INTERVAL_MS = 30 * 60 * 1000; 15 var FALLBACK_CACHE_MAX_AGE = 2 * 60 * 60 * 1000; 16 var REQUEST_TIMEOUT_MS = 10000; 17 var STORAGE_KEY = "reviewTrendingJson:v1"; 18 var ARTIST_STORAGE_KEY = "trendingArtistsJson:v1"; 19 20 if (rightNowContainer) { 21 rightNowContainer.addEventListener("click", openReviewLink); 22 rightNowContainer.addEventListener("keydown", openReviewLink); 23 } 24 load(); 25 26 function load() { 27 if (!window.fetch) { 28 renderAllFallbacks(); 29 return; 30 } 31 32 var controller = "AbortController" in window ? new AbortController() : null; 33 var timeout = controller 34 ? window.setTimeout(function () { controller.abort(); }, REQUEST_TIMEOUT_MS) 35 : null; 36 var options = { credentials: "same-origin", cache: "default" }; 37 if (controller) options.signal = controller.signal; 38 39 fetch(buildJsonUrl(), options) 40 .then(function (response) { 41 if (!response.ok) throw new Error("Trending JSON request failed"); 42 return response.json(); 43 }) 44 .then(function (data) { 45 clearRequestTimeout(timeout); 46 renderRightNowData(data); 47 renderArtistData(data); 48 renderFreeShippingData(data); 49 renderNewsData(data); 50 }) 51 .catch(function () { 52 clearRequestTimeout(timeout); 53 renderAllFallbacks(); 54 }); 55 } 56 57 function renderNewsData(data) { 58 if (!newsContainer || !data || !Array.isArray(data.news) || data.news.length !== 11) return; 59 var ids = {}; 60 var valid = data.news.every(function (item) { 61 var url = safeHttpUrl(item && item.url); 62 if (!item || typeof item.id !== 'string' || ids[item.id] || typeof item.text !== 'string' || !item.text.trim() 63 || !/^\d{4}-\d{2}-\d{2}$/.test(item.date) || item.displayDate !== item.date.replace(/-/g, '.') 64 || !url || new URL(url).hostname !== 'www.utsuwayayuuyuu.com' 65 || !/^(legacy|manual|new|restock)$/.test(item.type)) return false; 66 ids[item.id] = true; 67 return true; 68 }); 69 if (!valid) return; 70 var fragment = document.createDocumentFragment(); 71 data.news.forEach(function (item) { 72 var li = document.createElement('li'); 73 var a = document.createElement('a'); 74 var span = document.createElement('span'); 75 a.href = item.url; 76 a.appendChild(document.createTextNode(item.prefixText || '')); 77 span.textContent = item.displayDate; 78 a.appendChild(span); 79 a.appendChild(document.createTextNode(item.text)); 80 li.appendChild(a); 81 fragment.appendChild(li); 82 }); 83 newsContainer.replaceChildren(fragment); 84 } 85 86 function renderRightNowData(data) { 87 if (!rightNowContainer) return; 88 var items = normalizeItems(data && data.rightNow); 89 if (items.length !== MAX_ITEMS) { 90 renderRightNowFallback(); 91 return; 92 } 93 renderRightNow(items); 94 writeFallback(STORAGE_KEY, items); 95 } 96 97 function renderArtistData(data) { 98 if (!artistContainer) return; 99 var artists = normalizeArtists(data && data.artists); 100 if (!artists.length) { 101 renderArtistFallback(); 102 return; 103 } 104 renderArtists(artists); 105 writeFallback(ARTIST_STORAGE_KEY, artists); 106 } 107 108 function renderFreeShippingData(data) { 109 if (!freeShippingContainer) return; 110 var freeShipping = normalizeFreeShipping(data && data.freeShipping); 111 if (!freeShipping) { 112 renderFreeShippingFallback(); 113 return; 114 } 115 renderFreeShipping(freeShipping); 116 } 117 118 function buildJsonUrl() { 119 var url = new URL(JSON_PATH, document.baseURI); 120 var cacheBucket = Math.floor(Date.now() / JSON_CACHE_INTERVAL_MS);
121 url.searchParams.set("v", String(cacheBucket)); 122 return url.href; 123 } 124 125 function clearRequestTimeout(timeout) { 126 if (timeout !== null) window.clearTimeout(timeout); 127 } 128 129 function normalizeItems(items) { 130 if (!Array.isArray(items)) return []; 131 return items.map(normalizeRightNowItem).filter(Boolean).slice(0, MAX_ITEMS); 132 } 133 134 function normalizeRightNowItem(item) { 135 var url = safeHttpUrl(item && item.url); 136 var image = safeHttpUrl(item && item.image); 137 var stock = item && item.stock ? item.stock : {}; 138 if (!item || !item.productCode || !item.name || !url || !image || stock.available !== true) return null; 139 return { 140 productCode: String(item.productCode), 141 artist: String(item.artist || ""), 142 title: String(item.name), 143 url: url, 144 image: image, 145 price: String(item.price || ""), 146 stockCount: typeof stock.count === "number" ? stock.count : null, 147 reviewCount: typeof item.reviewCount === "number" ? item.reviewCount : 0, 148 ratingValue: typeof item.ratingValue === "number" ? item.ratingValue : 0, 149 description: String(item.description || "") 150 }; 151 } 152 153 function normalizeArtists(artists) { 154 if (!Array.isArray(artists)) return []; 155 return artists.map(function (artist) { 156 var url = safeHttpUrl(artist && artist.url); 157 var photo = safeHttpUrl(artist && artist.photo); 158 if (!artist || !artist.id || !artist.name || !artist.title || !url || !photo) return null; 159 var products = Array.isArray(artist.products) 160 ? artist.products.map(normalizeArtistProduct).filter(Boolean).slice(0, 5) 161 : []; 162 return { 163 id: String(artist.id), 164 name: String(artist.name), 165 title: String(artist.title), 166 photo: photo, 167 prefecture: String(artist.prefecture || ""), 168 country: String(artist.country || ""), 169 url: url, 170 products: products 171 }; 172 }).filter(Boolean); 173 } 174 175 function normalizeArtistProduct(item) { 176 var url = safeHttpUrl(item && item.url); 177 var mainImage = safeHttpUrl(item && (item.mainImage || item.image)); 178 var hoverImage = item && item.hoverImage ? safeHttpUrl(item.hoverImage) : ""; 179 var stock = item && item.stock ? item.stock : {}; 180 if (!item || !item.productCode || !item.name || !url || !mainImage || stock.available !== true) return null; 181 return { 182 productCode: String(item.productCode), 183 name: String(item.name), 184 url: url, 185 mainImage: mainImage, 186 hoverImage: hoverImage, 187 dimensions: String(item.dimensions || ""), 188 price: String(item.price || "") 189 }; 190 } 191 192 function normalizeFreeShipping(value) { 193 if (!value || value.selectionMode !== "main-sticky-sub-price" || !Array.isArray(value.items)) return null; 194 var main = value.main ? normalizeFreeShippingProduct(value.main, true) : null; 195 var items = value.items.map(function (item) { 196 return normalizeFreeShippingProduct(item, false); 197 }).filter(Boolean).slice(0, 4); 198 if (value.main && !main) return null; 199 return { main: main, items: items }; 200 } 201 202 function normalizeFreeShippingProduct(item, isMain) { 203 var url = safeHttpUrl(item && item.url); 204 var image = safeHttpUrl(item && item.image); 205 var stock = item && item.stock ? item.stock : {}; 206 if (!item || !item.productCode || !item.displayName || !url || !image || stock.available !== true) return null; 207 if (isMain && (!item.englishName || !item.description)) return null; 208 return { 209 productCode: String(item.productCode), 210 displayName: String(item.displayName), 211 englishName: String(item.englishName || ""), 212 description: String(item.description || ""), 213 url: url, 214 image: image, 215 price: String(item.price || "") 216 }; 217 } 218 219 function safeHttpUrl(value) { 220 try { 221 var url = new URL(String(value || ""), document.baseURI); 222 return url.protocol === "http:" || url.protocol === "https:" ? url.href : ""; 223 } catch (error) { 224 return ""; 225 } 226 } 227 228 function renderRightNow(items) { 229 rightNowContainer.innerHTML = items.map(function (item, index) { 230 return ( 231 '<div class="children order' + (index + 1) + '">' + 232 '<a href="' + escapeHtml(item.url) + '">' + 233 '<img loading="lazy" decoding="async" fetchpriority="low" src="' + escapeHtml(item.image) + '" alt="">' + 234 '<div class="trending-tags">' + renderReviewBadge(item) + renderStockBadge(item.stockCount) + "</div>" + 235 renderRating(item.ratingValue) + 236 "<h6>" + escapeHtml(parseCategory(item.title)) + "</h6>" + 237 '<p class="review-product-name">' + escapeHtml(item.title) + "</p>" + 238 (item.price ? '<p class="review-price">' + escapeHtml(item.price) + "</p>" : "") + 239 '<div class="detailWrap"><p>' + escapeHtml(item.description || makeDescription(item.title)) + "</p></div>" + 240 "</a></div>" 241 ); 242 }).join(""); 243 } 244 245 function renderArtists(artists) { 246 artistContainer.innerHTML = artists.map(function (artist, index) { 247 var rowClass = index === artists.length - 1 ? "artistNow2" : "artistNow"; 248 var location = [artist.prefecture, artist.country].filter(
248Boolean).join(","); 249 return ( 250 '<div class="' + rowClass + '" data-artist-id="' + escapeHtml(artist.id) + '">' + 251 '<div class="artistNow_icon"><a href="' + escapeHtml(artist.url) + '">' + 252 '<img loading="lazy" decoding="async" src="' + escapeHtml(artist.photo) + '" alt=""></a>' + 253 "<h6>" + escapeHtml(artist.title + "ï¼" + artist.name) + "</h6>" + 254 "<p>" + escapeHtml(location) + "</p></div>" + 255 '<ul class="arist-gallery">' + artist.products.map(renderArtistProduct).join("") + "</ul></div>" 256 ); 257 }).join(""); 258 initializeArtistImages(); 259 initializeArtistFlickity(); 260 if (window.sr && typeof window.sr.reveal === "function") { 261 window.sr.reveal(".artistNow_icon", { origin: "bottom", easing: "ease", distance: "5%", duration: 1000, scale: 1, delay: 200, opacity: 0 }); 262 } 263 } 264 265 function renderFreeShipping(freeShipping) { 266 var html = ""; 267 if (freeShipping.main) html += renderFreeShippingMain(freeShipping.main); 268 html += freeShipping.items.map(renderFreeShippingItem).join(""); 269 freeShippingContainer.innerHTML = html; 270 if (freeShippingSection) freeShippingSection.hidden = !freeShipping.main && !freeShipping.items.length; 271 } 272 273 function renderFreeShippingMain(item) { 274 return ( 275 '<div class="free-item1" data-product-code="' + escapeHtml(item.productCode) + '">' + 276 '<div class="free-item-image"><a href="' + escapeHtml(item.url) + '">' + 277 '<img loading="lazy" decoding="async" src="' + escapeHtml(item.image) + '" alt="' + escapeHtml(item.displayName) + '"></a></div>' + 278 '<div class="free-item-coment"><h5>' + escapeHtml(item.displayName) + "</h5>" + 279 "<h6>" + escapeHtml(item.englishName) + "</h6>" + 280 "<p>" + escapeHtml(item.description) + "</p>" + 281 "<p>" + escapeHtml(formatFreeShippingPrice(item.price)) + "</p></div></div>" 282 ); 283 } 284 285 function renderFreeShippingItem(item) { 286 return ( 287 '<div class="free-item2" data-product-code="' + escapeHtml(item.productCode) + '">' + 288 '<a href="' + escapeHtml(item.url) + '"><img loading="lazy" decoding="async" src="' + 289 escapeHtml(item.image) + '" alt="' + escapeHtml(item.displayName) + '">' + 290 "<p>" + escapeHtml(item.displayName) + "</p>" + 291 "<p>" + escapeHtml(formatFreeShippingPrice(item.price)) + "</p></a></div>" 292 ); 293 } 294 295 function renderArtistProduct(product) { 296 var hover = product.hoverImage ? ' data-hover-image="' + escapeHtml(product.hoverImage) + '"' : ""; 297 return ( 298 '<li class="gallery-cell"><a href="' + escapeHtml(product.url) + '">' + 299 '<img loading="lazy" decoding="async" src="' + escapeHtml(product.mainImage) + '"' + hover + ' alt="">' + 300 "<p>" + escapeHtml(cleanArtistProductName(product.name)) + "</p>" + 301 '<div class="size-date"><p>' + escapeHtml(product.dimensions) + "</p></div>" + 302 '<div class="price-date"><p>' + escapeHtml(formatArtistPrice(product.price)) + "</p></div>" + 303 "</a></li>" 304 ); 305 } 306 307 function initializeArtistImages() { 308 artistContainer.querySelectorAll("img[data-hover-image]").forEach(function (image) { 309 var mainImage = image.src; 310 var hoverImage = image.getAttribute("data-hover-image"); 311 image.addEventListener("mouseenter", function () { image.src = hoverImage; }); 312 image.addEventListener("mouseleave", function () { image.src = mainImage; }); 313 }); 314 } 315 316 function initializeArtistFlickity() { 317 if (!window.jQuery || !window.jQuery.fn || typeof window.jQuery.fn.flickity !== "function") return; 318 window.jQuery("#trendingArtistList .arist-gallery").each(function () { 319 var gallery = window.jQuery(this); 320 if (gallery.data("flickity")) return; 321 gallery.flickity({ watchCSS: true, prevNextButtons: false, cellAlign: "left" }); 322 gallery.find("img").each(function () { 323 var image = this; 324 var refresh = function () { 325 var instance = gallery.data("flickity"); 326 if (!instance || !gallery.hasClass("flickity-enabled")) return; 327 var cell = image.closest ? image.closest(".gallery-cell") : null; 328 if (cell && typeof instance.cellSizeChange === "function") instance.cellSizeChange(cell); 329 if (typeof instance.resize === "function") instance.resize(); 330 }; 331 image.addEventListener("load", refresh, { once: true }); 332 if (image.complete) window.setTimeout(refresh, 0); 333 }); 334 }); 335 } 336 337 function renderAllFallbacks() { 338 renderRightNowFallback(); 339 renderArtistFallback(); 340 renderFreeShippingFallback(); 341 } 342 343 function renderRightNowFallback() { 344 if (!rightNowContainer) return; 345 var items = readFallback(STORAGE_KEY, normalizeItems); 346 if (items.length === MAX_ITEMS) { 347 renderRightNow(items); 348 return; 349 } 350 rightNowContainer.innerHTML = '<p class="auto-trending-loading">ããããååãæºåä¸ã§ãã</p>'; 351 } 352 353 function renderArtistFallback() { 354 if (!artistContainer) return; 355 var artists = readFallback(ARTIST_STORAGE_KEY, normalizeArtists); 356 if (artists.length) renderArtists(artists); 357 } 358 359 function renderFreeShippingFallback() { 360 if (freeShippingContainer) freeShippingContainer.innerHTML = ""; 361 if (freeShippingSection) freeShippingSection.hidden = true; 362 } 363 364 function writeFallback(key, items) { 365 try { 366 getStorage().setItem(key, JSON.stringify({ savedAt: Date.now(), items: items })); 367 } catch (error) { 368 return; 369 } 370 } 371 372 function readFallback(key, normalize) { 373 try { 374 var cached = JSON.parse(getStorage().getItem(key) || "null"); 375 if (!cached || !cached.savedAt || Date.now() - cached.savedAt > FALLBACK_CACHE_MAX_AGE) return []; 376 return normalize(cached.items); 377 } catch (error) { 378 return []; 379 } 380 } 381 382 function getStorage() { 383 try { 384 if (window.localStorage) return window.localStorage; 385 } catch (error) { 386 return window.sessionStorage; 387 } 388 return window.sessionStorage; 389 } 390 391 function openReviewLink(event) { 392 var reviewLink = event.target.closest && event.target.closest(".review-jump-link"); 393 if (!reviewLink) return; 394 if (event.type === "keydown" && event.key !== "Enter" && event.key !== " ") return; 395 event.preventDefault(); 396 event.stopPropagation(); 397 window.location.href = reviewLink.getAttribute("data-review-url"); 398 } 399 400 function renderReviewBadge(item) { 401 if (!item.reviewCount) return ""; 402 return '<span class="review-jump-link" role="link" tabindex="0" aria-label="' + item.reviewCount + 403 'ä»¶ã®ã¬ãã¥ã¼ãè¦ã" data-review-url="' + escapeHtml(getReviewUrl(item.url)) + '"><b>' + 404 item.reviewCount + "</b>ä»¶ã®ã¬ãã¥ã¼</span>"; 405 } 406
407 function renderStockBadge(stockCount) { 408 return stockCount === 1 ? '<span class="stock-limited">1ç¹éã</span>' : ""; 409 } 410 411 function renderRating(ratingValue) { 412 if (!ratingValue) return ""; 413 var rating = Math.max(0, Math.min(5, Number(ratingValue))); 414 var rounded = Math.round(rating); 415 var stars = "â â â â â ".slice(0, rounded) + "âââââ".slice(0, 5 - rounded); 416 return '<p class="review-rating"><span class="review-rating-label">ãããã度ï¼</span>' + 417 '<span class="review-rating-stars">' + stars + "</span>" + 418 '<span class="review-rating-score">' + rating.toFixed(1) + "</span></p>"; 419 } 420 421 function getReviewUrl(url) { 422 return String(url || "").split("#")[0] + "#:~:text=" + encodeURIComponent("ã客æ§ã®ã¬ãã¥ã¼"); 423 } 424 425 function cleanArtistProductName(name) { 426 return String(name || "").replace(/\s*ä½å®¶\s*[ãã].*$/u, "").trim(); 427 } 428 429 function formatArtistPrice(price) { 430 var match = String(price || "").replace(/ï¿¥/g, "Â¥").match(/Â¥\s*([0-9,]+)/); 431 return match ? match[1] + "å" : String(price || ""); 432 } 433 434 function formatFreeShippingPrice(price) { 435 var match = String(price || "").replace(/ï¿¥/g, "Â¥").match(/Â¥\s*([0-9,]+)/); 436 return match ? "ç¨è¾¼" + match[1] + "å" : String(price || ""); 437 } 438 439 function parseCategory(title) { 440 if (title.indexOf("ã¬ã©ã¹") !== -1) return "ã¬ã©ã¹"; 441 if (title.indexOf("æ¼å¨") !== -1 || title.indexOf("æ¼") !== -1) return "æ¼å¨"; 442 if (title.indexOf("è±") !== -1 || title.indexOf("ä¸è¼ªæ¿ã") !== -1) return "é¶ç£å¨ã»ã¤ã³ããªã¢"; 443 if (title.indexOf("è¶ç¢") !== -1 || title.indexOf("æ¹è¶ç¢") !== -1) return "åé£å¨ï¼è¶ç¢"; 444 if (title.indexOf("ããå") !== -1 || title.indexOf("é ") !== -1 || title.indexOf("å¾³å©") !== -1) return "åé£å¨ï¼é å¨"; 445 if (title.indexOf("ç¿") !== -1) return "åé£å¨ï¼ç¿"; 446 return "åé£å¨"; 447 } 448 449 function makeDescription(title) { 450 if (title.indexOf("ã¬ã©ã¹") !== -1) return "éææã®ãããä½å®¶ã®æä»äºãæ¯ã¥ãã¬ã©ã¹ä½åã§ãã"; 451 if (title.indexOf("è±") !== -1 || title.indexOf("ä¸è¼ªæ¿ã") !== -1) return "空éã«è¡¨æ ãæ·»ãããä½å®¶ã®æä»äºã«ããè±å¨ã§ãã"; 452 return "ä½å®¶ã®æä»äºãæ¯ã¥ãä¸åã§ãã"; 453 } 454 455 function escapeHtml(value) { 456 return String(value || "") 457 .replace(/&/g, "&") 458 .replace(/</g, "<") 459 .replace(/>/g, ">") 460 .replace(/"/g, """) 461 .replace(/'/g, "'"); 462 } 463})();
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.