/** * 公開物件一覧・検索用: 画像 URL の正規化(削除は行わない)。 * ブロックリスト以外の https 外部(例: img4.athome.jp)は許可。http は https に昇格を試す。 * フォールバック用途: property | property-card | member-card */ (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.example.com']; function publicAsset(path) { if (typeof globalThis !== 'undefined' && globalThis.RakusumoPublicPath && typeof globalThis.RakusumoPublicPath.asset === 'function') { return globalThis.RakusumoPublicPath.asset(path); } var pre = typeof globalThis !== 'undefined' && typeof globalThis.__RAKUSUMO_PUBLIC_PATH_PREFIX__ === 'string' ? globalThis.__RAKUSUMO_PUBLIC_PATH_PREFIX__ : ''; return (pre === '' ? '' : pre) + '/' + String(path || '').replace(/^\/+/, ''); } var NO_IMAGE_RELS = { property: 'image/no-image-property.png', 'property-card': 'image/no-image-property-card.png', 'member-card': 'image/member-property-card.webp', 'member-top-card': 'image/member-propertyTOP-card.webp', }; var NO_IMAGE_VERSION_ATTRS = { property: 'data-property-no-image-v', 'property-card': 'data-property-card-no-image-v', 'member-card': 'data-member-card-no-image-v', 'member-top-card': 'data-member-top-card-no-image-v', }; function normalizeNoImageKind(kind) { kind = String(kind == null ? '' : kind) .trim() .toLowerCase(); if (kind === 'property-card' || kind === 'member-card' || kind === 'member-top-card') return kind; return 'property'; } function noImageCacheVersion(kind) { kind = normalizeNoImageKind(kind); var attrName = NO_IMAGE_VERSION_ATTRS[kind] || NO_IMAGE_VERSION_ATTRS.property; try { var fromDoc = document.documentElement && document.documentElement.getAttribute(attrName); if (fromDoc) return String(fromDoc).trim(); if (kind === 'property') { var meta = document.querySelector('meta[name="property-no-image-version"]'); if (meta) { var mv = String(meta.getAttribute('content') || '').trim(); if (mv) return mv; } } } catch (_e) {} return ''; } function noImageFallbackUrl(kind) { kind = normalizeNoImageKind(kind); if (kind === 'member-card' || kind === 'member-top-card') { return memberPropertyImageEffectiveUrl(kind); } if (kind === 'property-card') { try { var fromTopWin = String((window.__rakusumoCommonImages || {}).topNoImageUrl || '').trim(); if (fromTopWin) return fromTopWin; var fromTopDoc = document.documentElement.getAttribute('data-top-property-no-image-url'); if (fromTopDoc && String(fromTopDoc).trim()) return String(fromTopDoc).trim(); } catch (_eTop) {} } if (kind === 'property') { try { var fromPropertyWin = String((window.__rakusumoCommonImages || {}).noImageUrl || '').trim(); if (fromPropertyWin) return fromPropertyWin; var fromPropertyDoc = document.documentElement.getAttribute('data-property-no-image-url'); if (fromPropertyDoc && String(fromPropertyDoc).trim()) return String(fromPropertyDoc).trim(); } catch (_eProperty) {} } var path = publicAsset(NO_IMAGE_RELS[kind] || NO_IMAGE_RELS.property); var v = noImageCacheVersion(kind); return path + (v ? '?v=' + encodeURIComponent(v) : ''); } /** 会員限定案内カード画像(設定値 → 同梱フォールバック) */ function memberPropertyImageEffectiveUrl(kind) { kind = normalizeNoImageKind(kind || 'member-card'); var isTop = kind === 'member-top-card'; try { if (typeof window !== 'undefined' && window.__rakusumoCommonImages) { var fromWin = String( window.__rakusumoCommonImages[isTop ? 'topMemberPropertyImageUrl' : 'memberPropertyImageUrl'] || '', ).trim(); if (!fromWin && isTop) { fromWin = String(window.__rakusumoCommonImages.memberPropertyImageUrl || '').trim(); } if (fromWin) return fromWin; } var fromDoc = document.documentElement && document.documentElement.getAttribute( isTop ? 'data-top-member-property-image-url' : 'data-member-property-image-url', ); if (fromDoc && String(fromDoc).trim()) return String(fromDoc).trim(); if (isTop) { var fromMemberDoc = document.documentElement && document.documentElement.getAttribute('data-member-property-image-url'); if (fromMemberDoc && String(fromMemberDoc).trim()) return String(fromMemberDoc).trim(); } } catch (_e) {} var path = publicAsset(NO_IMAGE_RELS[kind] || NO_IMAGE_RELS['member-card']); var v = noImageCacheVersion(kind); return path + (v ? '?v=' + encodeURIComponent(v) : ''); } /** @deprecated 互換エイリアス */ function buildPropertyNoImageUrl() { return noImageFallbackUrl('property'); } var OWN_SITE_SUFFIXES = ['example.com', '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.example.com'); } 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 pathWithoutQuery(u) { var s = norm(u); var q = s.indexOf('?'); return q >= 0 ? s.slice(0, q) : s; } function bindCardImageFallback(imgEl) { if (!imgEl || imgEl.__ppuFallbackBound) return; imgEl.__ppuFallbackBound = true; if (!imgEl.getAttribute('data-no-image-kind')) { imgEl.setAttribute('data-no-image-kind', 'property'); } 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 kind = normalizeNoImageKind(imgEl.getAttribute('data-no-image-kind')); var fallback = noImageFallbackUrl(kind); var curPath = pathWithoutQuery(imgEl.getAttribute('src') || ''); var fbPath = pathWithoutQuery(fallback); imgEl.onerror = null; imgEl.classList.add('property-no-image-img'); imgEl.setAttribute('data-no-image-kind', kind); imgEl.alt = kind === 'member-card' ? '会員限定物件のご案内' : '物件画像は準備中です'; imgEl.removeAttribute('data-card-slide-img'); imgEl.removeAttribute('data-images'); imgEl.removeAttribute('data-image-kinds'); imgEl.removeAttribute('data-index'); if (curPath === fbPath) { return; } imgEl.src = fallback; }, { 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); }); } function resolveNoImageUrl(custom, kind) { var u = norm(custom); return u || noImageFallbackUrl(kind); } function imgOnerrorAttr(kind) { kind = normalizeNoImageKind(kind); var url = noImageFallbackUrl(kind).replace(/'/g, "\\'"); return ( ' data-no-image-kind="' + kind + '" onerror="this.onerror=null;this.src=\'' + url + '\';this.classList.add(\'property-no-image-img\');"' ); } return { sanitize: sanitize, fromImageCell: fromImageCell, bindCardImageFallback: bindCardImageFallback, bindAllCardImages: bindAllCardImages, noImageFallbackUrl: noImageFallbackUrl, memberPropertyImageEffectiveUrl: memberPropertyImageEffectiveUrl, resolveNoImageUrl: resolveNoImageUrl, imgOnerrorAttr: imgOnerrorAttr, normalizeNoImageKind: normalizeNoImageKind, BLOCKED_HOSTS: BLOCKED_HOSTS, OWN_SITE_SUFFIXES: OWN_SITE_SUFFIXES, get NO_IMAGE_PATHS() { return { property: publicAsset(NO_IMAGE_RELS.property), 'property-card': publicAsset(NO_IMAGE_RELS['property-card']), 'member-card': publicAsset(NO_IMAGE_RELS['member-card']), 'member-top-card': publicAsset(NO_IMAGE_RELS['member-top-card']), }; }, }; });