/** 付费文章:快速设置弹窗(填充、条件显隐、会员价校验、未保存提醒、防重复提交)。仅本页入队。 */ (function () { 'use strict'; var root = document.querySelector('.jio-products-page'); var dialog = document.getElementById('jio-product-editor'); if (!root || !dialog || typeof dialog.showModal !== 'function') return; var form = dialog.querySelector('[data-jio-product-form]'); var submit = form.querySelector('[data-jio-product-submit]'); var subject = form.querySelector('[data-jio-product-subject]'); var editLink = form.querySelector('[data-jio-product-edit-link]'); var submitLabel = submit.textContent; var opener = null; var snapshot = ''; var pointerStartedOutside = false; function field(key) { return form.querySelectorAll('[name="jio_pay[' + key + ']"]'); } function value(key) { var nodes = field(key); for (var i = 0; i < nodes.length; i += 1) { var node = nodes[i]; if (node.type === 'radio') { if (node.checked) return node.value; } else if (node.type === 'checkbox') { return node.checked ? node.value : ''; } else { return node.value; } } return ''; } function paneActive(name) { switch (name) { case 'enabled': return value('pay_type') !== 'no'; case 'disabled': return value('pay_type') === 'no'; case 'cash': return value('pay_modo') !== 'points'; case 'points': return value('pay_modo') === 'points'; case 'expire': return value('order_expired_s') === '1'; default: return true; } } /** 隐藏的分区连同其中的控件一起禁用:既不提交,也不参与必填校验。 */ function syncPanes() { form.querySelectorAll('[data-jio-product-pane]').forEach(function (pane) { var active = paneActive(pane.getAttribute('data-jio-product-pane')); pane.hidden = !active; if (pane.tagName === 'FIELDSET') pane.disabled = !active; }); form.querySelectorAll('input:not([type="hidden"]), select, textarea').forEach(function (control) { var node = control.parentElement; var disabled = false; while (node && node !== form) { if (node.hasAttribute('data-jio-product-pane') && node.hidden) { disabled = true; break; } node = node.parentElement; } control.disabled = disabled; }); syncVip(); } /** 现金按「分」比较,避免浮点误差。 */ function amount(raw, mode) { var text = String(raw || '').trim(); if (mode === 'points') return /^\d+$/.test(text) ? Number(text) : NaN; var match = text.match(/^(\d+)(?:\.(\d{1,2}))?$/); return match ? Number(match[1]) * 100 + Number((match[2] || '').padEnd(2, '0')) : NaN; } function syncVip() { ['cash', 'points'].forEach(function (mode) { var base = form.querySelector('[data-jio-product-base="' + mode + '"]'); var message = form.getAttribute(mode === 'points' ? 'data-vip-points-error' : 'data-vip-error'); form.querySelectorAll('[data-jio-product-vip="' + mode + '"]').forEach(function (input) { var vip = amount(input.value, mode); var limit = amount(base && base.value, mode); input.setCustomValidity(!input.disabled && vip > limit ? message : ''); }); }); } function serialize() { return new URLSearchParams(new FormData(form)).toString(); } function fill(payload) { var fields = payload.fields || {}; form.reset(); form.elements.post_id.value = String(payload.id || ''); Object.keys(fields).forEach(function (key) { var current = String(fields[key]); field(key).forEach(function (node) { if (node.type === 'radio') { node.checked = node.value === current; } else if (node.type === 'checkbox') { node.checked = current === '1'; } else { node.value = key === 'order_expired_time' && current === '0' ? '' : current; } }); }); subject.textContent = (payload.title || '') + ' · #' + String(payload.id || ''); editLink.hidden = !payload.editUrl; editLink.href = payload.editUrl || '#'; syncPanes(); } function lockScroll() { document.documentElement.classList.toggle('jio-products-modal-open', dialog.open); } function requestClose() { if (form.dataset.submitting) return; if (serialize() !== snapshot && !window.confirm(form.getAttribute('data-discard'))) return; dialog.close(); } root.addEventListener('click', function (event) { var button = event.target.closest('[data-jio-product-edit]'); if (!button || dialog.open) return; var payload; try { payload = JSON.parse(button.getAttribute('data-jio-product-edit')); } catch (error) { return; } opener = button; fill(payload); snapshot = serialize(); dialog.showModal(); lockScroll(); }); form.addEventListener('change', syncPanes); form.addEventListener('input', syncVip); function isOutside(event) { var rect = dialog.getBoundingClientRect(); return event.clientX < rect.left || event.clientX > rect.right || event.clientY < rect.top || event.clientY > rect.bottom; } dialog.addEventListener('pointerdown', function (event) { pointerStartedOutside = event.target === dialog && isOutside(event); }); dialog.addEventListener('click', function (event) { if (event.target.closest('[data-jio-dialog-close]') || (pointerStartedOutside && event.target === dialog && isOutside(event))) { event.preventDefault(); requestClose(); } pointerStartedOutside = false; }); dialog.addEventListener('cancel', function (event) { event.preventDefault(); requestClose(); }); dialog.addEventListener('close', function () { lockScroll(); if (opener && opener.isConnected) opener.focus(); opener = null; }); form.addEventListener('submit', function (event) { syncVip(); if (form.dataset.submitting || !form.checkValidity()) { event.preventDefault(); form.reportValidity(); return; } form.dataset.submitting = '1'; submit.textContent = form.getAttribute('data-busy-label'); // 延后禁用:同步禁用 submit 按钮会让部分浏览器丢掉这次提交。 setTimeout(function () { submit.disabled = true; }, 0); }); // bfcache 返回时恢复按钮,避免弹窗停在保存中状态。 window.addEventListener('pageshow', function () { delete form.dataset.submitting; submit.disabled = false; submit.textContent = submitLabel; lockScroll(); }); var highlighted = root.querySelector('.jio-products-table tr.is-highlight'); if (highlighted && typeof highlighted.scrollIntoView === 'function') { highlighted.scrollIntoView({ block: 'center' }); } })();