feat(pay): mirror reference resource row with copy, icon and reorder

The post editor's download row only exposed address / button text / remark,
leaving copy_key, copy_val and class as hidden inputs with no UI, so the
reference copy area, custom button icon, text and color were unreachable.
The submission popup already emitted those keys, which made the two write
paths diverge from anything the editor could produce.

Expose the full reference field set (地址/备注/复制名称/复制内容/图标/文案/
颜色) as an accordion card with drag reordering, add the one genuinely new
`icon` key through aksrt_sanitize_icon_value(), and teach both frontend
download renderers to consume the fields they previously ignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-09-24 20:27:30 +08:00
co-authored by Claude Sonnet 4.6
parent ab495854d5
commit b94c820361
10 changed files with 554 additions and 37 deletions
+150 -1
View File
@@ -4,6 +4,9 @@
var root = document.querySelector('[data-aksrt-pay-meta]');
if (!root) return;
var cfg = window.aksrtPayMetaBox || {};
var rowTitleFallback = (cfg.i18n && cfg.i18n.downloadUrl) || '下载地址';
function selected(name) {
var input = root.querySelector('input[name="aksrt_pay[' + name + ']"]:checked');
return input ? input.value : '';
@@ -79,6 +82,74 @@
frame.open();
}
function rowTitle(row) {
var label = row.querySelector('[data-group-label]');
var url = row.querySelector('[data-group-url]');
var text = label ? String(label.value || '').trim() : '';
if (text === '') {
text = url ? String(url.value || '').trim() : '';
}
return text !== '' ? text : rowTitleFallback;
}
function syncRowTitle(row) {
var title = row.querySelector('[data-group-title]');
if (title) title.textContent = rowTitle(row);
}
function syncRowColor(row) {
var input = row.querySelector('[data-group-class-input]');
if (!input) return;
var value = String(input.value || '');
row.querySelectorAll('[data-group-class]').forEach(function (swatch) {
var active = swatch.getAttribute('data-group-class') === value;
swatch.classList.toggle('is-active', active);
swatch.setAttribute('aria-pressed', active ? 'true' : 'false');
});
}
// Restore contiguous input names so PHP receives an ordered array after any
// reorder / removal instead of relying on DOM order. Anchored to this list's
// own group so sibling groups (attributes, video_episode) are never touched.
function reindexRows(list) {
var group = list.getAttribute('data-group-list') || '[^\\]]+';
var pattern = new RegExp('aksrt_pay\\[' + group + '\\]\\[\\d+\\]');
list.querySelectorAll('[data-group-row]').forEach(function (row, index) {
row.querySelectorAll('[name]').forEach(function (input) {
input.name = input.name.replace(pattern, 'aksrt_pay[' + group + '][' + index + ']');
});
});
}
function toggleRow(row, force) {
var open = typeof force === 'boolean' ? force : !row.classList.contains('is-open');
row.classList.toggle('is-open', open);
var toggle = row.querySelector('[data-group-toggle]');
if (toggle) toggle.setAttribute('aria-expanded', open ? 'true' : 'false');
}
function initRow(row) {
syncRowTitle(row);
syncRowColor(row);
var drag = row.querySelector('[data-group-drag]');
if (drag) drag.draggable = true;
}
function dragAfterElement(list, y) {
var rows = Array.prototype.slice.call(list.querySelectorAll('[data-group-row]:not(.is-dragging)'));
var best = null;
var bestOffset = -Infinity;
rows.forEach(function (row) {
var box = row.getBoundingClientRect();
var offset = y - box.top - box.height / 2;
if (offset < 0 && offset > bestOffset) {
bestOffset = offset;
best = row;
}
});
return best;
}
function addGroup(button) {
var id = button.getAttribute('data-group-add');
var list = root.querySelector('[data-group-list="' + id + '"]');
@@ -86,6 +157,11 @@
if (!list || !template) return;
var index = list.querySelectorAll('[data-group-row]').length;
list.insertAdjacentHTML('beforeend', template.innerHTML.replaceAll('__INDEX__', String(index)));
var added = list.lastElementChild;
if (added && added.hasAttribute('data-group-row')) {
initRow(added);
toggleRow(added, false);
}
}
root.addEventListener('click', function (event) {
@@ -122,15 +198,88 @@
addGroup(add);
return;
}
var toggle = target.closest('[data-group-toggle]');
if (toggle) {
event.preventDefault();
var toggleRowEl = toggle.closest('[data-group-row]');
if (toggleRowEl) toggleRow(toggleRowEl);
return;
}
var swatch = target.closest('[data-group-class]');
if (swatch) {
event.preventDefault();
var swatchRow = swatch.closest('[data-group-row]');
var classInput = swatchRow && swatchRow.querySelector('[data-group-class-input]');
if (classInput) {
classInput.value = swatch.getAttribute('data-group-class') || '';
syncRowColor(swatchRow);
}
return;
}
var remove = target.closest('[data-group-remove]');
if (remove) {
event.preventDefault();
var row = remove.closest('[data-group-row]');
var list = remove.closest('[data-group-list]');
if (row) row.remove();
if (list) reindexRows(list);
}
});
root.addEventListener('change', syncDependencies);
root.addEventListener('change', function (event) {
syncDependencies();
var row = event.target.closest && event.target.closest('[data-group-row]');
if (row && (event.target.hasAttribute('data-group-url') || event.target.hasAttribute('data-group-label'))) {
syncRowTitle(row);
}
});
root.addEventListener('input', function (event) {
var row = event.target.closest('[data-group-row]');
if (!row) return;
if (event.target.hasAttribute('data-group-label') || event.target.hasAttribute('data-group-url')) {
syncRowTitle(row);
}
});
root.addEventListener('dragstart', function (event) {
var row = event.target.closest && event.target.closest('[data-group-row]');
if (!row) return;
row.classList.add('is-dragging');
if (event.dataTransfer) {
event.dataTransfer.effectAllowed = 'move';
try {
event.dataTransfer.setData('text/plain', '');
} catch (error) { /* older IE */ }
}
});
root.addEventListener('dragend', function (event) {
var row = event.target.closest && event.target.closest('[data-group-row]');
if (!row) return;
row.classList.remove('is-dragging');
var list = row.closest('[data-group-list]');
if (list) reindexRows(list);
});
root.addEventListener('dragover', function (event) {
var list = event.target.closest ? event.target.closest('[data-group-list]') : null;
if (!list) return;
var dragging = list.querySelector('[data-group-row].is-dragging');
if (!dragging) return;
event.preventDefault();
var after = dragAfterElement(list, event.clientY);
if (after == null) {
list.appendChild(dragging);
} else if (after !== dragging) {
list.insertBefore(dragging, after);
}
});
root.querySelectorAll('[data-group-list]').forEach(function (list) {
list.querySelectorAll('[data-group-row]').forEach(initRow);
reindexRows(list);
});
renderGallery();
syncDependencies();
})();