/** * 公開物件一覧・検索用: 画像 URL の正規化(削除は行わない)。 * ブロックリスト以外の https 外部(例: img4.athome.jp)は許可。http は https に昇格を試す。 */ (function (root, factory) { if (typeof module === 'object' && module.exports) { module.exports = factory(); } else { root.PropertyPublicImageUrl = factory(); } })(typeof globalThis !== 'undefined' ? globalThis : this, function () { 'use strict'; var BLOCKED_HOSTS = ['img-asp.jp', 'www.img-asp.jp', 'kikitai.kodomonokuni.co.jp']; var OWN_SITE_SUFFIXES = ['kodomonokuni.co.jp', 'localhost', '127.0.0.1']; function norm(v) { return String(v == null ? '' : v).trim(); } function pageIsHttps() { try { return typeof location !== 'undefined' && location.protocol === 'https:'; } catch (_e) { return true; } } function hostBlocked(host) { host = norm(host).toLowerCase(); if (!host) return true; var bi; for (bi = 0; bi < BLOCKED_HOSTS.length; bi++) { var b = BLOCKED_HOSTS[bi]; if (host === b || host.slice(-(b.length + 1)) === '.' + b) return true; } return false; } function hostAllowed(host) { return !hostBlocked(host); } function normalizeRelative(path) { path = norm(path); if (!path) return ''; if (/^javascript:/i.test(path) || path.indexOf('blob:') === 0) return ''; if (/^data:image\//i.test(path)) return path; var lower = path.toLowerCase(); if (lower.indexOf('/ftptool/image/') === 0) return path; if (lower.indexOf('ftptool/image/') === 0) return '/' + path; if (lower.indexOf('/image/') === 0) return '/ftptool/image/' + path.slice('/image/'.length); if (lower.indexOf('image/') === 0) return '/ftptool/image/' + path.slice('image/'.length); if (path.charAt(0) === '/') return path; return ''; } function sanitize(raw, opts) { opts = opts || {}; var httpsOnly = opts.httpsOnly !== false ? pageIsHttps() : false; var u = norm(raw); if (!u) return ''; if (/^javascript:/i.test(u) || u.indexOf('blob:') === 0) return ''; if (/^data:image\//i.test(u)) return u; if (u.indexOf('//') === 0) { u = 'https:' + u; } if (!/^https?:\/\//i.test(u)) { return normalizeRelative(u); } var parsed; try { parsed = new URL(u, typeof location !== 'undefined' ? location.origin : 'https://www.kodomonokuni.co.jp'); } catch (_e) { return ''; } if (!hostAllowed(parsed.hostname)) return ''; if (httpsOnly && parsed.protocol === 'http:') { parsed.protocol = 'https:'; } return parsed.href; } function fromImageCell(img, opts) { if (!img) return ''; if (typeof img === 'string') return sanitize(img, opts); if (typeof img !== 'object') return ''; var keys = [ 'publicPath', 'url', 'src', 'originalPath', 'path', 'thumbnailUrl', 'thumbnail', 'thumbUrl', 'publicUrl', 'imageUrl', 'imageURL', 'link', 'href', 'originalUrl', 'remoteUrl', 'pictureUrl', 'externalUrl', 'atbbUrl', ]; var i; for (i = 0; i < keys.length; i++) { var s = sanitize(img[keys[i]], opts); if (s) return s; } return sanitize(img.fileName || img.filename, opts); } function bindCardImageFallback(imgEl) { if (!imgEl || imgEl.__ppuFallbackBound) return; imgEl.__ppuFallbackBound = true; imgEl.addEventListener( 'error', function onErr() { var images = []; var kinds = []; try { images = JSON.parse(imgEl.getAttribute('data-images') || '[]'); } catch (_e1) { images = []; } try { kinds = JSON.parse(imgEl.getAttribute('data-image-kinds') || '[]'); } catch (_e2) { kinds = []; } if (!Array.isArray(images)) images = []; var idx = Number(imgEl.getAttribute('data-index') || '0') || 0; var tried = Number(imgEl.getAttribute('data-ppu-tried') || '0') || 0; var next = idx + 1; while (next < images.length) { var candidate = sanitize(images[next]); if (candidate && candidate !== imgEl.getAttribute('src')) { imgEl.setAttribute('data-index', String(next)); imgEl.setAttribute('data-ppu-tried', String(tried + 1)); if (kinds[next] === 'floorplan') { imgEl.classList.add('is-floorplan'); imgEl.setAttribute('data-kind', 'floorplan'); } else { imgEl.classList.remove('is-floorplan'); imgEl.setAttribute('data-kind', 'photo'); } imgEl.src = candidate; return; } next++; } imgEl.removeEventListener('error', onErr); var wrap = imgEl.closest('.thumb-wrap, .list-card-thumb, .building-card__photo, .tp-list-card__photo'); if (wrap) { wrap.classList.add('list-card-thumb--empty'); var ph = document.createElement('div'); ph.className = 'thumb-placeholder property-no-image'; ph.setAttribute('role', 'img'); ph.setAttribute('aria-label', '画像準備中'); imgEl.replaceWith(ph); } }, { once: false }, ); } function bindAllCardImages(root) { var scope = root && root.querySelectorAll ? root : document; scope.querySelectorAll('.list-card-image[data-card-slide-img], .list-card-image').forEach(function (img) { bindCardImageFallback(img); }); } return { sanitize: sanitize, fromImageCell: fromImageCell, bindCardImageFallback: bindCardImageFallback, bindAllCardImages: bindAllCardImages, BLOCKED_HOSTS: BLOCKED_HOSTS, OWN_SITE_SUFFIXES: OWN_SITE_SUFFIXES, }; });