/* global window, document */ (function () { 'use strict'; function initGalleryThumbs() { var imgs = document.querySelectorAll('div.luxtools-gallery img[data-thumb-src]'); if (!imgs || !imgs.length) return; function loadThumb(img) { var src = img.getAttribute('data-thumb-src') || ''; if (!src) return; if (img.getAttribute('data-thumb-loading') === '1') return; img.setAttribute('data-thumb-loading', '1'); var pre = new window.Image(); pre.onload = function () { img.src = src; img.removeAttribute('data-thumb-src'); img.removeAttribute('data-thumb-loading'); }; pre.onerror = function () { img.removeAttribute('data-thumb-loading'); }; pre.src = src; } if ('IntersectionObserver' in window) { var io = new window.IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (!entry.isIntersecting) return; loadThumb(entry.target); io.unobserve(entry.target); }); }, { rootMargin: '200px' }); imgs.forEach(function (img) { io.observe(img); }); } else { // Fallback: load soon after initial render window.setTimeout(function () { imgs.forEach(loadThumb); }, 0); } } function getServiceUrl(el) { var url = el.getAttribute('data-service-url') || ''; url = (url || '').trim(); if (!url) return ''; // strip trailing slashes return url.replace(/\/+$/, ''); } function pingOpenViaImage(el, rawPath) { var baseUrl = getServiceUrl(el); if (!baseUrl) return; var url = baseUrl + '/open?path=' + encodeURIComponent(rawPath); // Fire-and-forget without CORS. try { var img = new window.Image(); img.src = url; } catch (e) { // ignore } } function openViaService(el, rawPath) { var baseUrl = getServiceUrl(el); if (!baseUrl) return Promise.reject(new Error('No client service configured')); var headers = { 'Content-Type': 'application/json' }; return window.fetch(baseUrl + '/open', { method: 'POST', mode: 'cors', credentials: 'omit', headers: headers, body: JSON.stringify({ path: rawPath }) }).then(function (res) { if (!res.ok) { return res.json().catch(function () { return null; }).then(function (body) { var msg = (body && body.message) ? body.message : ('HTTP ' + res.status); throw new Error(msg); }); } return res.json().catch(function () { return { ok: true }; }); }); } function normalizeToFileUrl(path) { if (!path) return ''; // already a file URL if (/^file:\/\//i.test(path)) return path; // UNC path: \\server\share\path if (/^\\\\/.test(path)) { var p = path.replace(/^\\\\/, ''); p = p.replace(/\\/g, '/'); return 'file://///' + p; } // Windows drive: C:\path\to\file if (/^[a-zA-Z]:\\/.test(path)) { var drive = path[0].toUpperCase(); var rest = path.slice(2).replace(/\\/g, '/'); return 'file:///' + drive + ':' + rest; } // POSIX absolute: /home/user/file if (path[0] === '/') { return 'file://' + path; } // Fall back to using the provided string. return path; } function onClick(event) { var el = event.target; if (!el || !el.classList || !el.classList.contains('luxtools-open')) return; var raw = el.getAttribute('data-path') || ''; if (!raw) return; // Prefer local client service. openViaService(el, raw) .catch(function (err) { // If the browser blocks the request before it reaches localhost (mixed-content, // extensions, stricter CORS handling), fall back to a no-CORS GET ping. pingOpenViaImage(el, raw); // Fallback to old behavior (often blocked in modern browsers). var url = normalizeToFileUrl(raw); if (!url) return; console.warn('Local client service failed, falling back to file:// navigation:', err); try { window.open(url, '_blank', 'noopener'); } catch (e) { try { window.location.href = url; } catch (e2) { console.error('Failed to open file URL:', e2); } } }); } document.addEventListener('click', onClick, false); document.addEventListener('DOMContentLoaded', initGalleryThumbs, false); })();