From 51a591e2b9a7f751d8565aeb339f39ac500a66c2 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 5 Sep 2026 23:41:22 +0800 Subject: [PATCH] feat(submit): add video cover picker with playable video preview Featured video preview now renders a real DPlayer (video-url/video-pic) like the reference theme instead of a static image, so the cover video plays on the submit page. Top-right bar gains the video-cover button shown only when a video cover is loaded; backend honors pic_id and no longer deletes the thumbnail before cover validation. Drop dead i18n keys and data-can-* attributes. --- .gitignore | 4 + assets/css/frontend/pages/submit.css | 20 ++--- assets/js/front-submit.js | 53 ++++++++++- src/Core/FrontSubmitFeatured.php | 27 ++++-- templates/pages/page-submit.php | 7 +- templates/parts/submit/featured.php | 22 +++-- .../video-cover-contract.test.cjs | 90 +++++++++++++++++++ 7 files changed, 188 insertions(+), 35 deletions(-) create mode 100644 tests/front-submit/video-cover-contract.test.cjs diff --git a/.gitignore b/.gitignore index 6e04fec2..16816dbc 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /.git/ /.claude/ /.compare/ +/.zcode/ # Project planning, internal docs, and local-only development files /.specs/ @@ -52,6 +53,9 @@ !/tests/widget-system/circular-button-icon-margin-contract.test.cjs !/tests/widget-system/single-cover-height-contract.test.cjs !/tests/widget-system/frontend-lifecycle-contract.test.cjs +!/tests/front-submit/ +/tests/front-submit/* +!/tests/front-submit/video-cover-contract.test.cjs !/tests/asset-ledger/ !/tests/asset-ledger/*.php !/tests/visual/docker-compose.zibll.yml diff --git a/assets/css/frontend/pages/submit.css b/assets/css/frontend/pages/submit.css index 016acc1b..c818ab3d 100644 --- a/assets/css/frontend/pages/submit.css +++ b/assets/css/frontend/pages/submit.css @@ -498,23 +498,13 @@ body.aksrt-editor-media-open { display: none; } -.featured-edit .featured-preview > img, -.featured-edit .featured-video-placeholder { +.featured-edit .featured-preview > img { display: block; width: 100%; aspect-ratio: 2 / 1; object-fit: cover; } -.featured-edit .featured-video-placeholder { - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - gap: 8px; - color: var(--muted-2-color, #999); -} - .featured-edit .featured-type-badge { position: absolute; right: 12px; @@ -557,6 +547,14 @@ body.aksrt-editor-media-open { font-size: 1em; } +.featured-edit .btns-full .btn-video-pic { + display: none; +} + +.featured-loaded.video .btns-full .btn-video-pic { + display: inline-flex; +} + .featured-loaded.image .btn-video, .featured-loaded.image .btn-slide, .featured-loaded.slide .btn-video, diff --git a/assets/js/front-submit.js b/assets/js/front-submit.js index 70f14183..1a0ece2e 100644 --- a/assets/js/front-submit.js +++ b/assets/js/front-submit.js @@ -400,6 +400,22 @@ 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) { @@ -424,12 +440,20 @@ '" alt="">'; } else if (t === 'video') { html = - (d.pic - ? '' - : '') + + '
' + + '
' + + '
' + ''; } + 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'; @@ -489,6 +513,27 @@ }); 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', @@ -509,7 +554,7 @@ type: 'image', multiple: false, allowExternal: false, - title: i18n.pickVideoCover || '选择视频封面(可选)', + title: i18n.setVideoCoverTitle || '为视频设置首图封面', onSelect: function (cover) { self.setFeatured('video', { url: video.url, diff --git a/src/Core/FrontSubmitFeatured.php b/src/Core/FrontSubmitFeatured.php index 34de8cb8..1ca75fb4 100644 --- a/src/Core/FrontSubmitFeatured.php +++ b/src/Core/FrontSubmitFeatured.php @@ -48,20 +48,35 @@ trait FrontSubmitFeatured { if ($video_id > 0 && !$this->can_use_front_submit_video($video_id, $user_id)) { $video_id = 0; } - $pic = esc_url_raw((string) ($payload['pic'] ?? '')); - if ($pic !== '' && !$this->user_can_cap('upload_submit_image', $user_id)) { - $pic = ''; + $pic_id = absint($payload['pic_id'] ?? 0); + if ($pic_id > 0 && !$this->can_use_front_submit_image($pic_id, $user_id)) { + $pic_id = 0; + } + $pic = ''; + if ($pic_id > 0) { + $pic = (string) wp_get_attachment_image_url($pic_id, 'full'); + } + if ($pic === '') { + $pic = esc_url_raw((string) ($payload['pic'] ?? '')); + if ($pic !== '' && !$this->can_use_front_submit_image_url($pic, $user_id)) { + $pic = ''; + } } $post_meta['featured_video'] = $video; $post_meta['featured_video_attachment_id'] = $video_id; $post_meta['featured_slide'] = ''; $post_meta['thumbnail_url'] = ''; $post_meta['cover_image'] = ''; - delete_post_thumbnail($post_id); - if ($pic !== '' && $this->can_use_front_submit_image_url($pic, $user_id)) { + if ($pic !== '') { $post_meta['thumbnail_url'] = $pic; $post_meta['cover_image'] = $pic; - $this->maybe_set_thumbnail_url($post_id, $pic); + if ($pic_id > 0) { + set_post_thumbnail($post_id, $pic_id); + } else { + $this->maybe_set_thumbnail_url($post_id, $pic); + } + } else { + delete_post_thumbnail($post_id); } break; diff --git a/templates/pages/page-submit.php b/templates/pages/page-submit.php index 09515c5c..697b521b 100644 --- a/templates/pages/page-submit.php +++ b/templates/pages/page-submit.php @@ -147,9 +147,8 @@ if (file_exists($js)) { 'fileTooLarge' => __('文件大小超过限制', 'aksrt'), 'lastSaved' => __('最后保存:', 'aksrt'), 'preview' => __('预览文章', 'aksrt'), - 'pickImage' => __('选择图片', 'aksrt'), - 'pickVideo' => __('选择视频封面图', 'aksrt'), - 'videoUrl' => __('请输入视频地址', 'aksrt'), + 'setVideoCover' => __('设置视频首图封面', 'aksrt'), + 'setVideoCoverTitle' => __('为视频设置首图封面', 'aksrt'), 'close' => __('关闭', 'aksrt'), 'insertImage' => __('插入图片', 'aksrt'), 'uploadImage' => __('上传图片', 'aksrt'), @@ -198,8 +197,6 @@ if (file_exists($js)) { 'maxMediaItems' => __('最多选择 %d 个文件', 'aksrt'), 'uploadingClose' => __('上传中,请稍候再关闭', 'aksrt'), 'mediaPickerUnavailable' => __('媒体选择器加载失败,请刷新页面后重试', 'aksrt'), - 'pickVideoResource' => __('选择视频资源', 'aksrt'), - 'pickVideoCover' => __('选择视频封面(可选)', 'aksrt'), 'download' => __('下载', 'aksrt'), 'quote' => __('引言', 'aksrt'), diff --git a/templates/parts/submit/featured.php b/templates/parts/submit/featured.php index 6ff80cde..be258163 100644 --- a/templates/parts/submit/featured.php +++ b/templates/parts/submit/featured.php @@ -22,10 +22,7 @@ $can_slide = !empty($ctx['can_cover_slide']); $can_video = !empty($ctx['can_cover_video']); ?>