fix(comments): render image upload progress like the reference
While uploading, the confirm button turned into a thin 3px bar below the label instead of the reference's striped overlay that fills the button. Two causes: - the markup used <span class="progress">; Bootstrap sizes the bar with a block-level .progress, so the swap produced a flattened line - shell.css carried a bespoke override pinning .progress to `position: static; height: 3px`, discarding the absolute full-size overlay that main.css already provides Changes: - emit the reference skeleton: <div class="progress progress-striped active"> > <div class="progress-bar progress-bar-success">, so the striped bar spans the button and the gradient shows through the translucent layer - give the upload button `position: relative` so the overlay is contained by the button rather than the dropdown panel; delete the static-line override - restore the reference's "正在处理请稍等..." toast and switch the label to "处理中 ..." at 100%, both keyed to the shared `miniupload_ajax` toast id so the completion message replaces the loading one - notify() now forwards the toast id instead of dropping it Tests: comment-image-upload contract gains two cases pinning the div-based striped overlay and the deletion of the 3px override; suite 835/836 with the pre-existing frontend-lifecycle failure. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
f6fde18857
commit
0007e78bfe
5 files changed
+66
-44
No files matched your search
@@ -249,25 +249,13 @@
|
||||
min-width: 88px;
|
||||
}
|
||||
|
||||
#comments .comment-image-upload .progress {
|
||||
position: static;
|
||||
inset: auto;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
margin-top: 4px;
|
||||
/* 上传中:按钮内容换成「加载点 + 文案 + 铺满按钮的条纹进度层」。
|
||||
按钮作为定位祖先,.progress 沿用 main.css 的绝对铺满(inset:0 / 100%)
|
||||
与负 z-index,progress-bar 走 Bootstrap 的 progress-bar-success 条纹;
|
||||
负层绘制在按钮背景之上、正文之下,因此文案与进度条同时可见。 */
|
||||
#comments .comment-image-upload .input-expand-upload {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
#comments .comment-image-upload .progress-bar {
|
||||
position: static;
|
||||
inset: auto;
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
#comments .comment-header .jio-identity-chip {
|
||||
display: inline-flex;
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
#comments .comment-box .comments-closed,#comments .action-text,#comments #cancel-comment-reply-link{display:none}#comments #postcomments .action-text,#comments #postcomments #cancel-comment-reply-link{display:inline-block}#comments .comt-title{width:90px}#comments .comt-title .comt-avatar .avatar{width:60px;height:60px}#comments #postcomments .comt-title{display:none}#respond:not(.mobile-fixed) #postcomments .comt-box{padding:5px 5px 4px;background:var(--main-bg-color);border-radius:4px;margin-top:12px}#comments #postcomments .comt-ctrl .but{margin-bottom:2px}#comments .list-inline{padding:15px}#comment{margin-bottom:5px}.comment-signarea{background:var(--main-shadow)}#respond+#postcomments .comment-filter,.comment-signarea+#postcomments .comment-filter{margin-top:20px}#postcomments .tab-nav-theme{margin-top:0}#postcomments .tab-nav-theme li{padding-bottom:1px}#postcomments .tab-nav-theme li:before{bottom:-2px}#postcomments .comment-footer{position:relative}#postcomments .avatar-img{--this-size: 45px;margin-right:20px}#postcomments .children .avatar-img{--this-size: 26px;vertical-align:2px;margin-right:6px}#postcomments .commentlist>.comment>.list-inline .author-box{align-items:start;margin-bottom:0;padding:0;background:none;border-radius:0;box-shadow:none}#postcomments .commentlist>.comment>.list-inline .comment-footer{margin-left:65px;margin-top:-25px}#postcomments .comment .list-inline>.comt-main{width:100%}#postcomments .commentlist .comment+.comment{border-top:1px solid var(--main-border-color)}#postcomments .comment .list-inline>li{padding:10px;vertical-align:top}#postcomments .comment-header{font-size:15px;position:relative}.comment-header .badge-status{margin-top:0;width:68px;z-index:0}#postcomments .action count{margin-left:4px}#postcomments .comt-meta>span:not(:empty){margin-right:10px;vertical-align:middle}#postcomments .comt-meta>span a{color:inherit}#postcomments .comt-meta>span .but{padding:.2em .8em}#postcomments .comment-approve-link.unapprove{color:#e87725}#postcomments .comment-approve-link.approve{color:#3695ff}#postcomments .comt-meta>span .comment-trash-link{color:#ff4b4b}#postcomments .children{list-style:none;padding-left:0;margin-left:86px;background:var(--main-shadow);border-radius:var(--main-radius);margin-bottom:6px}#postcomments .children .children{margin-left:23px}#postcomments .children .avatar-icontag{font-size:8px;height:14px;width:14px}.comment-content{word-wrap:break-word;white-space:pre-wrap}.comment-content .enlighter-default{margin-bottom:0;opacity:.9}#postcomments .comment-content img{max-width:260px;max-height:350px;display:block;width:auto;height:auto}#comments .virtual-input{display:none}.commentlist .no-more{margin:0;padding-bottom:10px}#comments .comment-image-tabs .comment-image-upload{margin:0}#comments .comment-image-upload-label{display:block;width:100%}#comments .comment-image-upload .preview{width:100%;height:96px;min-height:96px;margin-bottom:6px;overflow:hidden;border:1px dashed var(--muted-border-color);border-radius:var(--main-radius);background:var(--main-shadow)}#comments .comment-image-upload .preview img{display:block;width:100%;height:96px;object-fit:cover}#comments .comment-image-upload .input-expand-upload{min-width:88px}#comments .comment-image-upload .progress{position:static;inset:auto;display:block;width:100%;height:3px;margin-top:4px;overflow:hidden;border-radius:3px;background:#ffffff40}#comments .comment-image-upload .progress-bar{position:static;inset:auto;display:block;height:100%;width:0;transition:width .2s ease}#comments .comment-header .jio-identity-chip{display:inline-flex;align-items:center;gap:3px;vertical-align:middle;max-width:9em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}#comments .comment-header .jio-identity-medal{display:inline-block;width:auto;height:1.1em;max-width:6em;object-fit:contain;vertical-align:-.15em}@media(max-width:767px){#comments .virtual-input{display:flex;height:36px;border-radius:120px;background:var(--main-shadow);color:var(--muted-2-color)}.virtual-input .but,.virtual-input img{width:28px;height:28px;border-radius:120px;margin:0 4px;flex-shrink:0}.virtual-input .but{width:auto;padding:3px 10px}.drop-fixed-sm .dropdown-menu,.mobile-fixed{position:fixed;transform:translateY(220%);transition:.6s;opacity:1;left:0;right:0;bottom:0;padding:22px 16px;background:var(--main-bg-color);z-index:1080;border-radius:10px 10px 0 0;margin:0}.drop-fixed-sm.open .dropdown-menu,.mobile-fixed.show{box-shadow:0 -50px 50px #0003;transition:.6s cubic-bezier(.28,.9,.34,.99);transform:unset}.mobile-fixed.show .fixed-body{visibility:unset;z-index:-1}#respond.mobile-fixed{z-index:1040}.drop-fixed-sm .dropdown-menu{z-index:1045;padding:10px;top:auto!important;right:0!important;left:0!important;max-height:50vh;overflow:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch}.drop-fixed-sm .dropdown-menu>li>a{font-size:16px!important;padding:10px 20px}.modal-open .drop-fixed-sm.open .dropdown-menu{opacity:Line truncated
|
||||
#comments .comment-box .comments-closed,#comments .action-text,#comments #cancel-comment-reply-link{display:none}#comments #postcomments .action-text,#comments #postcomments #cancel-comment-reply-link{display:inline-block}#comments .comt-title{width:90px}#comments .comt-title .comt-avatar .avatar{width:60px;height:60px}#comments #postcomments .comt-title{display:none}#respond:not(.mobile-fixed) #postcomments .comt-box{padding:5px 5px 4px;background:var(--main-bg-color);border-radius:4px;margin-top:12px}#comments #postcomments .comt-ctrl .but{margin-bottom:2px}#comments .list-inline{padding:15px}#comment{margin-bottom:5px}.comment-signarea{background:var(--main-shadow)}#respond+#postcomments .comment-filter,.comment-signarea+#postcomments .comment-filter{margin-top:20px}#postcomments .tab-nav-theme{margin-top:0}#postcomments .tab-nav-theme li{padding-bottom:1px}#postcomments .tab-nav-theme li:before{bottom:-2px}#postcomments .comment-footer{position:relative}#postcomments .avatar-img{--this-size: 45px;margin-right:20px}#postcomments .children .avatar-img{--this-size: 26px;vertical-align:2px;margin-right:6px}#postcomments .commentlist>.comment>.list-inline .author-box{align-items:start;margin-bottom:0;padding:0;background:none;border-radius:0;box-shadow:none}#postcomments .commentlist>.comment>.list-inline .comment-footer{margin-left:65px;margin-top:-25px}#postcomments .comment .list-inline>.comt-main{width:100%}#postcomments .commentlist .comment+.comment{border-top:1px solid var(--main-border-color)}#postcomments .comment .list-inline>li{padding:10px;vertical-align:top}#postcomments .comment-header{font-size:15px;position:relative}.comment-header .badge-status{margin-top:0;width:68px;z-index:0}#postcomments .action count{margin-left:4px}#postcomments .comt-meta>span:not(:empty){margin-right:10px;vertical-align:middle}#postcomments .comt-meta>span a{color:inherit}#postcomments .comt-meta>span .but{padding:.2em .8em}#postcomments .comment-approve-link.unapprove{color:#e87725}#postcomments .comment-approve-link.approve{color:#3695ff}#postcomments .comt-meta>span .comment-trash-link{color:#ff4b4b}#postcomments .children{list-style:none;padding-left:0;margin-left:86px;background:var(--main-shadow);border-radius:var(--main-radius);margin-bottom:6px}#postcomments .children .children{margin-left:23px}#postcomments .children .avatar-icontag{font-size:8px;height:14px;width:14px}.comment-content{word-wrap:break-word;white-space:pre-wrap}.comment-content .enlighter-default{margin-bottom:0;opacity:.9}#postcomments .comment-content img{max-width:260px;max-height:350px;display:block;width:auto;height:auto}#comments .virtual-input{display:none}.commentlist .no-more{margin:0;padding-bottom:10px}#comments .comment-image-tabs .comment-image-upload{margin:0}#comments .comment-image-upload-label{display:block;width:100%}#comments .comment-image-upload .preview{width:100%;height:96px;min-height:96px;margin-bottom:6px;overflow:hidden;border:1px dashed var(--muted-border-color);border-radius:var(--main-radius);background:var(--main-shadow)}#comments .comment-image-upload .preview img{display:block;width:100%;height:96px;object-fit:cover}#comments .comment-image-upload .input-expand-upload{min-width:88px}#comments .comment-image-upload .input-expand-upload{position:relative;overflow:hidden}#comments .comment-header .jio-identity-chip{display:inline-flex;align-items:center;gap:3px;vertical-align:middle;max-width:9em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px}#comments .comment-header .jio-identity-medal{display:inline-block;width:auto;height:1.1em;max-width:6em;object-fit:contain;vertical-align:-.15em}@media(max-width:767px){#comments .virtual-input{display:flex;height:36px;border-radius:120px;background:var(--main-shadow);color:var(--muted-2-color)}.virtual-input .but,.virtual-input img{width:28px;height:28px;border-radius:120px;margin:0 4px;flex-shrink:0}.virtual-input .but{width:auto;padding:3px 10px}.drop-fixed-sm .dropdown-menu,.mobile-fixed{position:fixed;transform:translateY(220%);transition:.6s;opacity:1;left:0;right:0;bottom:0;padding:22px 16px;background:var(--main-bg-color);z-index:1080;border-radius:10px 10px 0 0;margin:0}.drop-fixed-sm.open .dropdown-menu,.mobile-fixed.show{box-shadow:0 -50px 50px #0003;transition:.6s cubic-bezier(.28,.9,.34,.99);transform:unset}.mobile-fixed.show .fixed-body{visibility:unset;z-index:-1}#respond.mobile-fixed{z-index:1040}.drop-fixed-sm .dropdown-menu{z-index:1045;padding:10px;top:auto!important;right:0!important;left:0!important;max-height:50vh;overflow:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch}.drop-fixed-sm .dropdown-menu>li>a{font-size:16px!important;padding:10px 20px}.modal-open .drop-fixed-sm.open .dropdown-menu{opacity:0}.drop-fixed-sm .dropdown-menu:before{display:none}}@media(max-width:640px){#comments .comt-title{display:none}#comments .comt-box{width:100%;padding:0}#comments .list-inline{padding:15px 0;margin:0}.comment-signarea h3{Line truncated
|
||||
@@ -39,25 +39,13 @@
|
||||
min-width: 88px;
|
||||
}
|
||||
|
||||
#comments .comment-image-upload .progress {
|
||||
position: static;
|
||||
inset: auto;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
margin-top: 4px;
|
||||
/* 上传中:按钮内容换成「加载点 + 文案 + 铺满按钮的条纹进度层」。
|
||||
按钮作为定位祖先,.progress 沿用 main.css 的绝对铺满(inset:0 / 100%)
|
||||
与负 z-index,progress-bar 走 Bootstrap 的 progress-bar-success 条纹;
|
||||
负层绘制在按钮背景之上、正文之下,因此文案与进度条同时可见。 */
|
||||
#comments .comment-image-upload .input-expand-upload {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
}
|
||||
|
||||
#comments .comment-image-upload .progress-bar {
|
||||
position: static;
|
||||
inset: auto;
|
||||
display: block;
|
||||
height: 100%;
|
||||
width: 0;
|
||||
transition: width 0.2s ease;
|
||||
}
|
||||
#comments .comment-header .jio-identity-chip {
|
||||
display: inline-flex;
|
||||
|
||||
@@ -26,9 +26,9 @@
|
||||
textarea.dispatchEvent(new Event('input'));
|
||||
}
|
||||
|
||||
function notify(message, type) {
|
||||
function notify(message, type, id) {
|
||||
if (typeof window.notyf === 'function') {
|
||||
window.notyf(message, type);
|
||||
window.notyf(message, type, '', id || '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,6 +127,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
/** 参考主题的上传中骨架:加载点 + 文案 + 铺满按钮的条纹进度层。 */
|
||||
function pendingMarkup() {
|
||||
return '<span class="miniupload-ing">'
|
||||
+ '<i class="loading mr3 c-white"></i>'
|
||||
+ '<span class="loading-text c-white">上传中<count class="px12 ml3"></count></span>'
|
||||
+ '<div class="progress progress-striped active"><div class="progress-bar progress-bar-success" role="progressbar" style="width:0"></div></div>'
|
||||
+ '</span>';
|
||||
}
|
||||
|
||||
function uploadErrorToast(message) {
|
||||
notify(message, 'danger', 'miniupload_ajax');
|
||||
}
|
||||
|
||||
function uploadImage(button) {
|
||||
var form = button.closest('.comment-image-upload');
|
||||
if (!form) return;
|
||||
@@ -153,7 +166,12 @@
|
||||
state.uploading = true;
|
||||
button.disabled = true;
|
||||
input.disabled = true;
|
||||
button.innerHTML = '<span class="miniupload-ing"><i class="loading mr3 c-white"></i><span class="loading-text c-white">上传中<count class="px12 ml3"></count></span><span class="progress progress-striped active"><span class="progress-bar progress-bar-success" role="progressbar" style="width:0"></span></span></span>';
|
||||
// 进度条与文案替换按钮内容;同时弹出参考主题的「正在处理」提示。
|
||||
button.innerHTML = pendingMarkup();
|
||||
// 复用固定 id:上传结束时由成功/失败提示替换这条加载态提示。
|
||||
if (typeof window.notyf === 'function') {
|
||||
window.notyf('正在处理请稍等...', 'load', '', 'miniupload_ajax');
|
||||
}
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('POST', uploadUrl, true);
|
||||
@@ -167,7 +185,7 @@
|
||||
var loadingText = button.querySelector('.loading-text');
|
||||
if (count) count.textContent = percent + '%';
|
||||
if (progress) progress.style.width = percent + '%';
|
||||
if (percent >= 100 && loadingText) loadingText.firstChild.nodeValue = '处理中';
|
||||
if (percent >= 100 && loadingText) loadingText.innerHTML = '处理中 ...';
|
||||
};
|
||||
|
||||
xhr.onload = function () {
|
||||
@@ -178,20 +196,20 @@
|
||||
|
||||
if (xhr.status < 200 || xhr.status >= 300 || typeof url !== 'string' || url.length < 6) {
|
||||
var message = response && response.message ? response.message : '图片上传失败';
|
||||
notify(message, 'danger');
|
||||
uploadErrorToast(message);
|
||||
restoreUploadButton(button, originalHtml);
|
||||
resetUpload(form);
|
||||
return;
|
||||
}
|
||||
|
||||
notify(response.message || '图片已上传', 'success');
|
||||
notify(response.message || '图片已上传', 'success', 'miniupload_ajax');
|
||||
insertAtCursor(findTextarea(button), '[img=' + url + ']\n');
|
||||
restoreUploadButton(button, originalHtml);
|
||||
resetUpload(form);
|
||||
};
|
||||
|
||||
xhr.onerror = function () {
|
||||
notify('网络错误,图片上传失败', 'danger');
|
||||
uploadErrorToast('网络错误,图片上传失败');
|
||||
restoreUploadButton(button, originalHtml);
|
||||
resetUpload(form);
|
||||
};
|
||||
|
||||
@@ -78,3 +78,31 @@ test('built comment assets carry the upload contract and no removed submit handl
|
||||
assert.match(commentsCss, /progress-bar/);
|
||||
assert.doesNotMatch(runtimeBundle, /handleResponse/);
|
||||
});
|
||||
|
||||
test('上传中骨架与参考主题一致:Bootstrap 条纹进度层铺满按钮', () => {
|
||||
// 参考结构:<span class="miniupload-ing"> + <div class="progress progress-striped active">
|
||||
// 内层 <div class="progress-bar progress-bar-success">,用 div 而非 span。
|
||||
assert.match(
|
||||
tools,
|
||||
/'<span class="miniupload-ing">'[\s\S]{0,400}'<div class="progress progress-striped active"><div class="progress-bar progress-bar-success" role="progressbar" style="width:0"><\/div><\/div>'/,
|
||||
'上传中骨架必须复用参考主题的 miniupload-ing + Bootstrap 条纹进度层'
|
||||
);
|
||||
assert.doesNotMatch(tools, /<span class="progress progress-striped/, '进度层必须是 div,span 会破坏 Bootstrap 的块级布局');
|
||||
assert.match(tools, /window\.notyf\('正在处理请稍等\.\.\.', 'load', '', 'miniupload_ajax'\)/, '上传开始应弹出参考主题的「正在处理」提示');
|
||||
assert.match(tools, /loadingText\.innerHTML = '处理中 \.\.\.'/, '到达 100% 后文案切换为「处理中 ...」');
|
||||
});
|
||||
|
||||
test('上传按钮提供定位上下文,并去掉自造的静态细条覆盖', () => {
|
||||
const shell = read('assets/css/frontend/comments/shell.css');
|
||||
assert.match(
|
||||
shell,
|
||||
/#comments \.comment-image-upload \.input-expand-upload \{[\s\S]*?position: relative;/,
|
||||
'.progress 是绝对铺满层,按钮必须是定位祖先'
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
shell,
|
||||
/#comments \.comment-image-upload \.progress \{[\s\S]{0,200}position: static/,
|
||||
'不得再把 .progress 改成静态细条(偏离参考主题)'
|
||||
);
|
||||
assert.doesNotMatch(shell, /height: 3px;[\s\S]{0,80}#comments \.comment-image-upload \.progress/, '自造的 3px 细条已删除');
|
||||
});
|
||||
Reference in new issue
Block a user