(function (root, factory) { var api = factory(); if (typeof module === 'object' && module.exports) { module.exports = api; } if (root) { root.TaberebaSettings = api; } }(typeof window !== 'undefined' ? window : globalThis, function () { 'use strict'; var storageKey = 'tabereba_settings_v1'; var maxSites = 20; var templates = ['amazlet-1', 'amazlet-2', 'amazlet-3', 'amazlet-4', 'gtools-1', 'gtools-2', 'gtools-3', 'mokari-1']; function emptySite() { return {site_name: '', hotpepper_valuecommerce_html: '', tabelog_valuecommerce_html: '', gnavi_linkshare_html: '', image_size: 'medium', shop_label_suffix: '', template_key: 'amazlet-2', shop_icon_type: 'none', custom_css_preset: 'simple', show_catch: true, show_address: true, show_tabelog: true, show_gnavi: true, background_opacity: 100, migration_info: {}}; } function defaultSettings() { return {service: 'tabereba', schema_version: 1, version: 1, default_site_index: 0, active_site_index: 0, sites: [emptySite()]}; } function allowed(value, values, fallback) { return values.indexOf(value) !== -1 ? value : fallback; } function normalizeSite(value) { var site = emptySite(); value = value && typeof value === 'object' ? value : {}; site.site_name = typeof value.site_name === 'string' ? value.site_name.trim().slice(0, 100) : ''; ['hotpepper_valuecommerce_html', 'tabelog_valuecommerce_html', 'gnavi_linkshare_html'] .forEach(function (key) { if (typeof value[key] === 'string' && value[key].length <= 8192) { site[key] = value[key].trim(); } }); site.image_size = allowed(value.image_size, ['large', 'medium', 'small'], 'medium'); site.shop_label_suffix = allowed(value.shop_label_suffix, ['', 'で予約する', 'で探す', 'で見る', 'で検索'], ''); site.template_key = allowed(value.template_key, templates, 'amazlet-2'); site.shop_icon_type = allowed(value.shop_icon_type, ['none', 'hotpepper', 'simple1', 'simple2', 'simple3', 'simple4', 'simple5', 'simple6'], 'none'); site.custom_css_preset = allowed(value.custom_css_preset, ['simple', 'shop-color'], 'simple'); site.show_catch = typeof value.show_catch === 'boolean' ? value.show_catch : true; site.show_address = typeof value.show_address === 'boolean' ? value.show_address : true; site.show_tabelog = typeof value.show_tabelog === 'boolean' ? value.show_tabelog : true; site.show_gnavi = typeof value.show_gnavi === 'boolean' ? value.show_gnavi : true; site.background_opacity = allowed(parseInt(value.background_opacity, 10), [100, 90, 80, 70, 60, 50], 100); if (value.migration_info && value.migration_info.source === 'legacy_cookie') { site.migration_info = { source: 'legacy_cookie', needs_affiliate_review: value.migration_info.needs_affiliate_review !== false, incomplete_valuecommerce_pairs: Array.isArray(value.migration_info.incomplete_valuecommerce_pairs) ? value.migration_info.incomplete_valuecommerce_pairs.filter(function (key) { return key === 'hotpepper'; }) : [], migrated_at: typeof value.migration_info.migrated_at === 'string' ? value.migration_info.migrated_at.slice(0, 40) : '', reviewed_at: typeof value.migration_info.reviewed_at === 'string' ? value.migration_info.reviewed_at.slice(0, 40) : '' }; } return site; } function normalizeSettings(value) { if (!value || typeof value !== 'object' || value.service !== 'tabereba' || value.schema_version !== 1 || value.version !== 1 || !Array.isArray(value.sites) || value.sites.length < 1) { return defaultSettings(); } var sites = value.sites.slice(0, maxSites).map(normalizeSite); var active = parseInt(value.active_site_index, 10); var selectedDefault = parseInt(value.default_site_index, 10); active = isNaN(active) || active < 0 || active >= sites.length ? 0 : active; selectedDefault = isNaN(selectedDefault) || selectedDefault < 0 || selectedDefault >= sites.length ? 0 : selectedDefault; return {service: 'tabereba', schema_version: 1, version: 1, default_site_index: selectedDefault, active_site_index: active, sites: sites}; } function load(storage) { try { return normalizeSettings(JSON.parse(storage.getItem(storageKey) || 'null')); } catch (error) { return defaultSettings(); } } function save(storage, settings) { try { storage.setItem(storageKey, JSON.stringify(normalizeSettings(settings))); return true; } catch (error) { return false; } } function initialize() { var settings = load(window.localStorage); var siteSelect = document.getElementById('tb-site-select'); var siteName = document.getElementById('tb-site-name'); var addSite = document.getElementById('tb-add-site'); var deleteSite = document.getElementById('tb-delete-site'); var status = document.getElementById('tb-settings-status'); var generateStatus = document.getElementById('tb-generate-status'); var generateForm = document.querySelector('.tb-generate-form'); var migrationNotice = document.getElementById('tb-legacy-migration-notice'); var migrationNoticeText = document.getElementById('tb-legacy-migration-notice-text'); var markMigrationReviewed = document.getElementById('tb-mark-legacy-reviewed'); var affiliateFields = { hotpepper_valuecommerce_html: document.getElementById('tb-hotpepper-mylink'), tabelog_valuecommerce_html: document.getElementById('tb-tabelog-mylink'), gnavi_linkshare_html: document.getElementById('tb-gnavi-mylink') }; var saveTimer = null; var previewTimer = null; var previewRequest = 0; if (!siteSelect || !siteName || !addSite || !deleteSite) { return; } function showStatus(message) { status.textContent = message; } function fillSettingsJson() { var json = JSON.stringify(settings); document.querySelectorAll('.user_settings_json').forEach(function (field) { field.value = json; }); } function selectValue(id, value) { var field = document.getElementById(id); if (field) { field.value = String(value); } } function checkValue(name, value) { document.querySelectorAll('[name="' + name + '"]').forEach(function (field) { if (field.type === 'radio') { field.checked = field.value === String(value); } }); } function updateAvailability() { var template = document.getElementById('tb-generate-template'); var custom = template && template.value === 'amazlet-2'; document.querySelectorAll('[name="generate_custom_css_preset"]').forEach(function (field) { field.disabled = !custom; }); var icon = document.getElementById('tb-generate-icon'); if (icon) { icon.disabled = custom; icon.title = custom ? 'amazlet風-2ではショップアイコンを表示しません。' : ''; } var help = document.getElementById('tb-css-preset-help'); if (help) { help.textContent = custom ? '生成CSSへ選択したプリセットを反映します。' : 'CSSプリセットはamazlet風-2だけで使用できます。'; } } function updateAffiliateStatus(key, value) { var names = {hotpepper_valuecommerce_html: 'hotpepper', tabelog_valuecommerce_html: 'tabelog', gnavi_linkshare_html: 'gnavi'}; var hosts = {hotpepper: ['www.hotpepper.jp'], tabelog: ['tabelog.com', 'www.tabelog.com'], gnavi: ['r.gnavi.co.jp', 'www.gnavi.co.jp']}; var service = names[key]; var target = document.querySelector('[data-affiliate-status="' + service + '"]'); var validators = window.TaberebaAffiliateLinkValidators; var valid = value !== '' && validators && (service === 'gnavi' ? validators.linkshare(value, hosts[service]) : validators.valueCommerce(value, hosts[service])); if (service === 'tabelog' || service === 'gnavi') { setShopOptionAvailability(service, Boolean(valid)); } if (target) { target.classList.toggle('is-valid', Boolean(valid)); var hiddenMessage = service === 'hotpepper' ? '通常リンクを使用' : 'ボタンは表示されません'; target.textContent = value === '' ? '未設定(' + hiddenMessage + ')' : (valid ? '入力形式は有効です(自動保存済み)' : '形式を確認してください(' + hiddenMessage + ')'); } } function setShopOptionAvailability(service, available) { var option = document.getElementById('tb-show-' + service + '-option'); if (option) { option.hidden = !available; } } function render() { siteSelect.textContent = ''; settings.sites.forEach(function (site, index) { var option = document.createElement('option'); option.value = String(index); option.textContent = site.site_name || 'サイト' + (index + 1); option.selected = index === settings.active_site_index; siteSelect.appendChild(option); }); var site = settings.sites[settings.active_site_index]; siteName.value = site.site_name; Object.keys(affiliateFields).forEach(function (key) { affiliateFields[key].value = site[key]; updateAffiliateStatus(key, site[key]); }); checkValue('generate_image_size', site.image_size); checkValue('generate_custom_css_preset', site.custom_css_preset); selectValue('tb-generate-suffix', site.shop_label_suffix); selectValue('tb-generate-template', site.template_key); selectValue('tb-generate-icon', site.shop_icon_type); selectValue('tb-generate-opacity', site.background_opacity); var catchField = document.querySelector('[name="generate_show_catch"][value="1"]'); var addressField = document.querySelector('[name="generate_show_address"][value="1"]'); var tabelogField = document.querySelector('[name="generate_show_tabelog"][value="1"]'); var gnaviField = document.querySelector('[name="generate_show_gnavi"][value="1"]'); if (catchField) { catchField.checked = site.show_catch; } if (addressField) { addressField.checked = site.show_address; } if (tabelogField) { tabelogField.checked = site.show_tabelog; } if (gnaviField) { gnaviField.checked = site.show_gnavi; } if (migrationNotice) { var migration = site.migration_info || {}; var needsReview = migration.source === 'legacy_cookie' && migration.needs_affiliate_review !== false; migrationNotice.hidden = !needsReview; if (needsReview && migrationNoticeText) { migrationNoticeText.textContent = (migration.incomplete_valuecommerce_pairs || []).indexOf('hotpepper') !== -1 ? '旧CookieのHot Pepper sid・pidに不整合があったため、ASP設定は移行されていません。入力欄を確認してください。' : '旧Cookieから再構成したHot Pepper MyLinkです。ValueCommerce管理画面の現行HTMLと照合してください。'; } } updateAvailability(); fillSettingsJson(); } function collect() { var site = settings.sites[settings.active_site_index]; site.site_name = siteName.value.trim().slice(0, 100); Object.keys(affiliateFields).forEach(function (key) { site[key] = affiliateFields[key].value.trim().slice(0, 8192); updateAffiliateStatus(key, site[key]); }); if (generateForm) { var imageSize = generateForm.querySelector('[name="generate_image_size"]:checked'); var cssPreset = generateForm.querySelector('[name="generate_custom_css_preset"]:checked'); var catchField = generateForm.querySelector('[name="generate_show_catch"][value="1"]'); var addressField = generateForm.querySelector('[name="generate_show_address"][value="1"]'); var tabelogField = generateForm.querySelector('[name="generate_show_tabelog"][value="1"]'); var gnaviField = generateForm.querySelector('[name="generate_show_gnavi"][value="1"]'); site.image_size = imageSize ? imageSize.value : site.image_size; site.shop_label_suffix = document.getElementById('tb-generate-suffix').value; site.template_key = document.getElementById('tb-generate-template').value; site.shop_icon_type = document.getElementById('tb-generate-icon').value; site.custom_css_preset = cssPreset ? cssPreset.value : site.custom_css_preset; site.show_catch = Boolean(catchField && catchField.checked); site.show_address = Boolean(addressField && addressField.checked); site.show_tabelog = Boolean(tabelogField && tabelogField.checked); site.show_gnavi = Boolean(gnaviField && gnaviField.checked); site.background_opacity = parseInt(document.getElementById('tb-generate-opacity').value, 10) || 100; } settings.sites[settings.active_site_index] = normalizeSite(site); } function persist(message) { collect(); if (!save(window.localStorage, settings)) { showStatus('設定を保存できませんでした。ブラウザの保存設定を確認してください。'); return false; } settings = load(window.localStorage); fillSettingsJson(); showStatus(message); return true; } function mobileDocument(css, html) { return '
' + '' + html + ''; } function regenerate(delay) { if (!generateForm) { return; } window.clearTimeout(previewTimer); previewTimer = window.setTimeout(function () { var requestId = ++previewRequest; fillSettingsJson(); var data = new FormData(generateForm); data.append('ajax_generate', '1'); generateStatus.textContent = 'プレビューを更新しています…'; fetch('index.php', {method: 'POST', body: data, credentials: 'same-origin'}) .then(function (response) { return response.json(); }) .then(function (result) { if (requestId !== previewRequest || !result.success) { if (requestId === previewRequest) { generateStatus.textContent = result.message || 'プレビューを更新できませんでした。'; } return; } document.getElementById('tb-generated-preview').innerHTML = result.html; document.getElementById('tb-generated-preview-css').textContent = result.css; document.getElementById('tb-generated-mobile-preview').srcdoc = mobileDocument(result.css, result.html); document.getElementById('tb-output-card').value = result.card_html; document.getElementById('tb-output-text').value = result.text_html; document.getElementById('tb-output-text-preview').innerHTML = result.text_preview_html; document.getElementById('tb-output-image').value = result.image_html; var imagePreview = document.getElementById('tb-output-image-preview'); imagePreview.innerHTML = result.image_preview_html; imagePreview.hidden = result.image_preview_html === ''; document.getElementById('tb-output-image-help').hidden = result.image_html !== ''; document.getElementById('tb-output-css').value = result.css; document.getElementById('tb-output-css-row').hidden = result.css === ''; if (result.affiliate_availability) { setShopOptionAvailability('tabelog', result.affiliate_availability.tabelog === true); setShopOptionAvailability('gnavi', result.affiliate_availability.gnavi === true); } var shopField = generateForm.querySelector('[name="shop_json"]'); if (shopField && result.shop) { shopField.value = JSON.stringify(result.shop); } document.dispatchEvent(new CustomEvent('tabereba:shop-generated', { detail: result.shop || null })); generateStatus.textContent = '自動保存し、プレビューを更新しました。'; }) .catch(function () { generateStatus.textContent = 'プレビューを更新できませんでした。もう一度変更してください。'; }); }, typeof delay === 'number' ? delay : 80); } function saveAndRegenerate(message, delay) { if (persist(message)) { updateAvailability(); regenerate(delay); } } document.querySelectorAll('[data-preview-device]').forEach(function (button) { button.addEventListener('click', function () { var device = button.getAttribute('data-preview-device'); document.querySelectorAll('[data-preview-device]').forEach(function (item) { var active = item === button; item.classList.toggle('is-active', active); item.setAttribute('aria-pressed', active ? 'true' : 'false'); }); document.querySelectorAll('[data-preview-panel]').forEach(function (panel) { panel.hidden = panel.getAttribute('data-preview-panel') !== device; }); }); }); siteName.addEventListener('input', function () { window.clearTimeout(saveTimer); saveTimer = window.setTimeout(function () { saveAndRegenerate('サイト名を自動保存しました。', 40); render(); }, 350); }); Object.keys(affiliateFields).forEach(function (key) { affiliateFields[key].addEventListener('input', function () { updateAffiliateStatus(key, affiliateFields[key].value.trim()); window.clearTimeout(saveTimer); saveTimer = window.setTimeout(function () { saveAndRegenerate('MyLink設定を自動保存しました。', 40); }, 450); }); affiliateFields[key].addEventListener('change', function () { saveAndRegenerate('MyLink設定を自動保存しました。', 40); }); }); siteSelect.addEventListener('change', function () { var next = parseInt(siteSelect.value, 10); siteSelect.value = String(settings.active_site_index); collect(); settings.active_site_index = next; if (save(window.localStorage, settings)) { settings = load(window.localStorage); render(); showStatus('選択したサイトへ切り替えました。'); regenerate(40); } }); addSite.addEventListener('click', function () { collect(); if (settings.sites.length >= maxSites) { showStatus('サイト設定は20件までです。'); return; } settings.sites.push(emptySite()); settings.active_site_index = settings.sites.length - 1; save(window.localStorage, settings); render(); showStatus('新しいサイト設定を追加しました。'); regenerate(40); }); deleteSite.addEventListener('click', function () { if (settings.sites.length <= 1) { showStatus('サイト設定は最低1件必要です。'); return; } if (!window.confirm('選択中のサイト設定を削除します。よろしいですか?')) { return; } settings.sites.splice(settings.active_site_index, 1); settings.active_site_index = Math.min(settings.active_site_index, settings.sites.length - 1); settings.default_site_index = Math.min(settings.default_site_index, settings.sites.length - 1); save(window.localStorage, settings); render(); showStatus('サイト設定を削除しました。'); regenerate(40); }); if (markMigrationReviewed) { markMigrationReviewed.addEventListener('click', function () { var site = settings.sites[settings.active_site_index]; if (!site.migration_info || site.migration_info.source !== 'legacy_cookie') { return; } site.migration_info.needs_affiliate_review = false; site.migration_info.reviewed_at = new Date().toISOString(); if (persist('移行したASP設定を確認済みとして保存しました。')) { render(); } }); } if (generateForm) { generateForm.querySelectorAll('[name^="generate_"]').forEach(function (field) { field.addEventListener('change', function () { saveAndRegenerate('表示設定を自動保存しました。', 40); }); }); ['tb-edit-title', 'tb-edit-search-keyword'].forEach(function (id) { var field = document.getElementById(id); field.addEventListener('input', function () { regenerate(450); }); field.addEventListener('change', function () { regenerate(40); }); }); } save(window.localStorage, settings); settings = load(window.localStorage); render(); regenerate(40); } if (typeof document !== 'undefined') { document.addEventListener('DOMContentLoaded', initialize); } return {emptySite: emptySite, defaultSettings: defaultSettings, normalizeSite: normalizeSite, normalizeSettings: normalizeSettings, load: load, save: save, storageKey: storageKey, maxSites: maxSites}; }));