Files
wordpress-theme-aksrt/assets/js/front-submit.js
T
kate522 daee4cd67f feat(submit): make video cover row icon-only with hover titles
Replace the video-pic/video/clear button labels with icon-only buttons
carrying title + aria-label (设置视频封面/视频/清除), center the glyphs
via flex to fix the upward icon shift, rename the media picker title to
为视频设置封面, and drop the unused setVideoCover i18n key. Contract
test updated to pin the new markup and string set.
2026-09-06 10:10:12 +08:00

693 lines
22 KiB
JavaScript

/**
* AKSRT front-end article submit (write/post page).
* Handles TinyMCE content, featured cover, pay box, draft/submit AJAX.
*
* @package AKSRT
*/
/* global notyf */
(function () {
'use strict';
var cfg = window.aksrtSubmitData || {};
var i18n = cfg.i18n || {};
var ajaxUrl = cfg.ajaxUrl || '/wp-admin/admin-ajax.php';
var nonce = cfg.nonce || '';
function qs(sel, root) {
return (root || document).querySelector(sel);
}
function qsa(sel, root) {
return Array.prototype.slice.call((root || document).querySelectorAll(sel));
}
function escapeHtml(value) {
return String(value || '')
.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}
function getEditorContent() {
if (window.tinymce) {
var ed = window.tinymce.get('post_content');
if (ed) {
return ed.getContent();
}
}
var ta = qs('#post_content') || qs('[name="post_content"]');
return ta ? ta.value : '';
}
function serializeForm(form) {
var data = {};
var fd = new FormData(form);
fd.forEach(function (value, key) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
if (!Array.isArray(data[key])) {
data[key] = [data[key]];
}
data[key].push(value);
} else {
data[key] = value;
}
});
return data;
}
function toFormBody(obj) {
var params = new URLSearchParams();
function append(key, val) {
if (val === undefined || val === null) {
return;
}
if (Array.isArray(val)) {
val.forEach(function (v) {
append(key, v);
});
return;
}
if (typeof val === 'object') {
Object.keys(val).forEach(function (k) {
append(key + '[' + k + ']', val[k]);
});
return;
}
params.append(key, String(val));
}
Object.keys(obj).forEach(function (k) {
append(k, obj[k]);
});
return params;
}
var App = {
form: null,
isDirty: false,
isSubmitting: false,
featured: { type: '', data: {} },
init: function () {
this.form = document.getElementById('aksrt-submit-form');
if (!this.form || this.form.getAttribute('data-aksrt-submit-ready') === '1') {
return;
}
this.form.setAttribute('data-aksrt-submit-ready', '1');
this.bindDirty();
this.bindAutoHeight();
this.bindSubmitButtons();
this.bindDraftDelete();
this.bindFeatured();
this.bindPay();
this.bindLeaveWarning();
this.bindAi();
this.bindTagActive();
this.loadFeaturedFromDom();
},
bindDirty: function () {
var self = this;
this.form.addEventListener('input', function () {
self.isDirty = true;
self.form.setAttribute('data-dirty', 'true');
});
if (window.tinymce) {
var tryBind = function () {
var ed = window.tinymce.get('post_content');
if (ed) {
ed.on('change keyup', function () {
self.isDirty = true;
});
} else {
setTimeout(tryBind, 400);
}
};
tryBind();
}
},
bindLeaveWarning: function () {
var self = this;
if (cfg.leaveWarning === false) {
return;
}
window.addEventListener('beforeunload', function (e) {
if (self.isDirty && !self.isSubmitting && !window.post_is_save) {
e.preventDefault();
e.returnValue = i18n.confirmLeave || '';
}
});
},
bindAutoHeight: function () {
qsa('[data-auto-height]').forEach(function (el) {
var max = parseInt(el.getAttribute('data-max-height') || '78', 10);
var resize = function () {
el.style.height = 'auto';
el.style.height = Math.min(el.scrollHeight, max) + 'px';
};
el.addEventListener('input', resize);
resize();
});
},
bindTagActive: function () {
qsa('.aksrt-submit-tag input, .newpost-filter-tags input').forEach(function (input) {
var sync = function () {
var tag = input.closest('.aksrt-submit-tag, .tag-list');
if (tag) {
tag.classList.toggle('is-active', input.checked);
tag.classList.toggle('active', input.checked);
}
};
input.addEventListener('change', sync);
sync();
});
},
bindSubmitButtons: function () {
var self = this;
qsa('.aksrt-submit-btn', this.form).forEach(function (btn) {
btn.addEventListener('click', function (e) {
e.preventDefault();
if (self.isSubmitting) {
return;
}
self.submit(btn, btn.getAttribute('data-action') || 'posts_save');
});
});
this.form.addEventListener('submit', function (e) {
e.preventDefault();
});
},
collectPayload: function (action) {
var data = serializeForm(this.form);
data.action = action === 'posts_draft' ? 'aksrt_save_draft' : 'aksrt_submit_post';
data._nonce = nonce || data._nonce || '';
data.post_content = getEditorContent();
data.post_title = data.post_title || ((qs('#submit-title') && qs('#submit-title').value) || '');
data.status = action === 'posts_draft' ? 'draft' : 'pending';
data.submit_action = action;
var featuredJson = qs('[data-featured-json]', this.form);
if (featuredJson && featuredJson.value) {
try {
data.featured_data = JSON.parse(featuredJson.value);
} catch (err) {
data.featured_data = this.featured;
}
} else if (this.featured && this.featured.type) {
data.featured_data = this.featured;
}
return data;
},
submit: function (btn, action) {
var self = this;
if (action !== 'posts_draft') {
var captcha = window.AKSRTCaptcha;
if (captcha && !btn.dataset.aksrtCaptchaReady) {
captcha.run('front_submit', this.form).then(function (payload) {
if (payload === null) return;
btn.dataset.aksrtCaptchaReady = '1';
self.submit(btn, action);
}).catch(function () {
captcha.reset('front_submit', self.form);
notyf(i18n.error || '人机验证失败,请重试', 'danger');
});
return;
}
delete btn.dataset.aksrtCaptchaReady;
}
this.isSubmitting = true;
var toastId = action === 'posts_draft'
? 'aksrt-front-submit-draft-toast'
: 'aksrt-front-submit-publish-toast';
var original = btn.innerHTML;
btn.disabled = true;
btn.innerHTML =
'<i class="fa fas fa-spinner fa-spin"></i> ' +
(action === 'posts_draft' ? i18n.saving || 'Saving...' : i18n.submitting || 'Submitting...');
notyf(
action === 'posts_draft' ? i18n.saving || '正在保存草稿…' : i18n.submitting || '正在提交文章…',
'load',
'',
toastId
);
var payload = this.collectPayload(action);
if (payload.featured_data && typeof payload.featured_data === 'object') {
payload.featured_data = JSON.stringify(payload.featured_data);
}
fetch(ajaxUrl, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
body: toFormBody(payload),
})
.then(function (r) {
return r.json();
})
.then(function (res) {
var ok = !!(res && res.success);
var d = (res && (res.data || res)) || {};
if (!ok) {
throw new Error((d && d.message) || i18n.error || 'Error');
}
self.isDirty = false;
window.post_is_save = true;
if (d.posts_id || d.post_id) {
var hid = self.form.querySelector('input[name="posts_id"]');
if (hid) {
hid.value = String(d.posts_id || d.post_id);
}
}
if (d.time) {
var timeEl = qs('.aksrt-submit-modified-time');
if (timeEl) {
timeEl.textContent = '';
var timeBadge = document.createElement('span');
timeBadge.className = 'badg';
timeBadge.textContent = (i18n.lastSaved || '最后保存:') + d.time;
timeEl.appendChild(timeBadge);
}
}
if (d.url) {
var view = qs('.aksrt-submit-view-btn');
if (view) {
view.textContent = '';
var previewLink = document.createElement('a');
previewLink.className = 'but c-blue';
previewLink.target = '_blank';
previewLink.rel = 'noopener';
previewLink.href = String(d.url);
var previewIcon = document.createElement('i');
previewIcon.className = 'fa fas fa-file-alt';
previewLink.appendChild(previewIcon);
previewLink.appendChild(document.createTextNode(' ' + (i18n.preview || 'Preview')));
view.appendChild(previewLink);
}
}
notyf(
d.message || (action === 'posts_draft' ? i18n.saved || '草稿已保存' : i18n.submitted || '投稿已提交'),
'success',
5,
toastId
);
if (d.goto) {
setTimeout(function () {
window.location.href = d.goto;
}, 1000);
return;
}
if (d.reload) {
setTimeout(function () {
window.location.reload();
}, 1000);
return;
}
setTimeout(function () {
btn.disabled = false;
btn.innerHTML = original;
self.isSubmitting = false;
}, 300);
})
.catch(function (err) {
notyf(err.message || i18n.error || '操作失败,请重试', 'danger', 5, toastId);
btn.disabled = false;
btn.innerHTML = original;
self.isSubmitting = false;
})
.finally(function () {
if (action !== 'posts_draft' && window.AKSRTCaptcha) {
window.AKSRTCaptcha.reset('front_submit', self.form);
}
});
},
bindDraftDelete: function () {
document.addEventListener('click', function (e) {
var btn = e.target.closest('.aksrt-submit-drafts__delete');
if (!btn) {
return;
}
e.preventDefault();
var id = btn.getAttribute('data-draft-id');
if (!id) {
return;
}
if (!window.confirm(i18n.confirmDelete || 'Delete?')) {
return;
}
var toastId = 'aksrt-front-submit-delete-draft-toast';
btn.disabled = true;
notyf(i18n.deleting || '正在删除草稿…', 'load', '', toastId);
fetch(ajaxUrl, {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
body: toFormBody({ action: 'aksrt_delete_draft', _nonce: nonce, draft_id: id }),
})
.then(function (r) {
return r.json();
})
.then(function (res) {
if (res && res.success) {
var item = btn.closest('.aksrt-submit-drafts__item');
if (item) {
item.remove();
}
notyf((res.data && res.data.message) || i18n.deleted || '草稿已删除', 'success', 5, toastId);
} else {
btn.disabled = false;
notyf((res && res.data && res.data.message) || i18n.error || '删除失败', 'danger', 5, toastId);
}
})
.catch(function () {
btn.disabled = false;
notyf(i18n.error || '网络错误,请重试', 'danger', 5, toastId);
});
});
},
loadFeaturedFromDom: function () {
var box = qs('.featured-edit, .aksrt-submit-featured');
if (!box) {
return;
}
var raw = box.getAttribute('data-featured-args');
if (!raw) {
return;
}
try {
var args = JSON.parse(raw);
if (args && args.type) {
this.featured = { type: args.type, data: args.data || {} };
}
} catch (e) {}
},
setFeatured: function (type, data) {
this.featured = { type: type || '', data: data || {} };
var jsonInput = qs('[data-featured-json]');
if (jsonInput) {
jsonInput.value = JSON.stringify(this.featured);
}
this.renderFeaturedPreview();
this.isDirty = true;
},
destroyFeaturedPlayer: function (preview) {
var old = qs('.new-dplayer', preview);
if (!old || !window.jQuery) {
return;
}
var dp = window.jQuery(old).data('dplayer');
if (dp) {
if (typeof dp.pause === 'function') {
dp.pause();
}
if (typeof dp.destroy === 'function') {
dp.destroy();
}
}
},
renderFeaturedPreview: function () {
var preview = qs('[data-featured-preview]');
if (!preview) {
return;
}
var t = this.featured.type;
var d = this.featured.data || {};
var box = qs('.featured-edit');
if (box) {
box.classList.remove('featured-loaded', 'image', 'slide', 'video');
if (t && t !== 'close') {
box.classList.add('featured-loaded', t);
}
}
var html = '';
if (t === 'image' && d.url) {
html = '<img src="' + escapeHtml(d.url) + '" alt="">';
} else if (t === 'slide' && Array.isArray(d) && d[0] && d[0].url) {
html =
'<img src="' +
escapeHtml(d[0].url) +
'" alt=""><span class="featured-type-badge"><i class="fa fas fa-image"></i></span>';
} else if (t === 'video') {
html =
'<div class="new-dplayer dplayer-scale-height" style="--scale-height:50%;" video-url="' +
escapeHtml(d.url || '') +
'" video-pic="' +
escapeHtml(d.pic || '') +
'"><div class="graphic" style="padding-bottom:50%;">' +
'<div class="abs-center text-center"><i class="fa fas fa-play-circle fa-4x muted-3-color opacity5" aria-hidden="true"></i></div>' +
'</div></div>' +
'<span class="featured-type-badge"><i class="fa fas fa-video"></i></span>';
}
this.destroyFeaturedPlayer(preview);
preview.innerHTML = html;
if (t === 'video' && typeof window.auto_fun === 'function') {
window.auto_fun();
}
var clearBtn = qs('[data-featured-action="close"]');
if (clearBtn) {
clearBtn.hidden = !t || t === 'close';
}
},
openMediaPicker: function (options) {
if (!window.AksrtSubmitMedia || typeof window.AksrtSubmitMedia.open !== 'function') {
notyf(i18n.mediaPickerUnavailable || '媒体选择器加载失败,请刷新页面后重试', 'danger');
return false;
}
window.AksrtSubmitMedia.open(options);
return true;
},
bindFeatured: function () {
var self = this;
var box = qs('.featured-edit, .aksrt-submit-featured');
if (!box) {
return;
}
box.addEventListener('click', function (e) {
var btn = e.target.closest('[data-featured-action]');
if (!btn) {
return;
}
e.preventDefault();
var act = btn.getAttribute('data-featured-action');
if (act === 'close') {
self.setFeatured('close', {});
return;
}
if (act === 'image') {
self.openMediaPicker({
type: 'image',
multiple: false,
allowExternal: false,
onSelect: function (item) {
if (!item) return;
self.setFeatured('image', { url: item.url || '', id: item.attachment_id || item.id || 0 });
},
});
return;
}
if (act === 'slide') {
self.openMediaPicker({
type: 'image',
multiple: true,
maxItems: 30,
allowExternal: false,
onSelect: function (items) {
var slides = (Array.isArray(items) ? items : []).map(function (item) {
return { url: item.url || '', id: item.attachment_id || item.id || 0 };
}).filter(function (item) { return item.url || item.id; });
if (slides.length) self.setFeatured('slide', slides);
},
});
return;
}
if (act === 'video_pic') {
var current = self.featured;
if (current.type !== 'video' || !current.data || !current.data.url) {
return;
}
self.openMediaPicker({
type: 'image',
multiple: false,
allowExternal: false,
title: i18n.setVideoCoverTitle || '为视频设置封面',
onSelect: function (cover) {
self.setFeatured('video', {
url: current.data.url,
pic: cover && cover.url ? cover.url : '',
pic_id: cover ? (cover.attachment_id || cover.id || 0) : 0,
id: current.data.id || 0,
});
},
});
return;
}
if (act === 'video') {
self.openMediaPicker({
type: 'video',
multiple: false,
allowExternal: true,
allowEmbed: false,
onSelect: function (item) {
if (!item || !item.url) return;
var video = {
url: item.url,
pic: '',
pic_id: 0,
id: item.attachment_id || item.id || 0,
};
self.setFeatured('video', video);
window.setTimeout(function () {
self.openMediaPicker({
type: 'image',
multiple: false,
allowExternal: false,
title: i18n.setVideoCoverTitle || '为视频设置封面',
onSelect: function (cover) {
self.setFeatured('video', {
url: video.url,
pic: cover && cover.url ? cover.url : '',
pic_id: cover ? (cover.attachment_id || cover.id || 0) : 0,
id: video.id,
});
},
});
}, 0);
},
});
}
});
},
bindPay: function () {
var box = qs('[data-pay-box]');
if (!box) {
return;
}
var toggle = qs('[data-pay-toggle]', box);
var fields = qs('[data-pay-fields]', box);
var offHint = qs('[data-pay-off-hint]', box);
var modoInput = qs('[data-pay-modo-input]', box);
var cash = qs('[data-pay-cash]', box);
var points = qs('[data-pay-points]', box);
function syncToggle() {
var on = toggle && toggle.checked;
if (fields) {
fields.hidden = !on;
}
if (offHint) {
offHint.hidden = !!on;
}
}
if (toggle) {
toggle.addEventListener('change', syncToggle);
}
syncToggle();
qsa('[data-pay-modo]', box).forEach(function (btn) {
btn.addEventListener('click', function () {
var v = btn.getAttribute('data-pay-modo') || '0';
if (modoInput) {
modoInput.value = v;
}
qsa('[data-pay-modo]', box).forEach(function (b) {
b.classList.toggle('active', b === btn);
});
if (cash) {
cash.hidden = v === 'points';
}
if (points) {
points.hidden = v !== 'points';
}
});
});
window.aksrtSubmitPayDownloads.init({
root: box,
notify: notyf,
markDirty: function () {
App.isDirty = true;
App.form.setAttribute('data-dirty', 'true');
},
});
},
bindAi: function () {
var ai = cfg.ai || {};
if (!ai.available) {
return;
}
qsa('.aksrt-ai-assist-btn').forEach(function (btn) {
btn.hidden = false;
btn.addEventListener('click', function () {
var action = btn.getAttribute('data-ai-action');
var content = getEditorContent();
if (!content || content.replace(/<[^>]+>/g, '').trim().length < 10) {
notyf(i18n.needContent || '请先填写正文内容', 'warning');
return;
}
var toastId = action === 'tags'
? 'aksrt-front-submit-ai-tags-toast'
: 'aksrt-front-submit-ai-summary-toast';
var old = btn.textContent;
btn.disabled = true;
btn.textContent = i18n.aiGenerating || '...';
notyf(i18n.aiGenerating || '正在生成…', 'load', '', toastId);
fetch((cfg.restUrl || '').replace(/\/$/, '') + '/ai/' + action, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': cfg.restNonce || '',
},
body: JSON.stringify({ content: content }),
})
.then(function (r) {
return r.json();
})
.then(function (res) {
var text = (res && (res.data || res).text) || (res && res.result) || '';
if (!text) {
throw new Error(i18n.aiFailed || 'AI failed');
}
if (action === 'summary') {
var ex = qs('[name="excerpt"]');
if (ex) {
ex.value = text;
}
} else if (action === 'tags') {
var tags = qs('[name="tags"]');
if (tags) {
tags.value = text;
}
}
notyf(i18n.aiFilled || '已填入,可继续编辑', 'success', 5, toastId);
})
.catch(function (err) {
notyf(err.message || i18n.aiFailed || 'AI 生成失败', 'danger', 5, toastId);
})
.finally(function () {
btn.disabled = false;
btn.textContent = old;
});
});
});
},
};
jQuery(document).off('auto_fun.aksrt-front-submit').on('auto_fun.aksrt-front-submit', function () { App.init(); });
})();