diff --git a/assets/css/build/comments.css b/assets/css/build/comments.css index d95debd2..4f3a2f1e 100644 --- a/assets/css/build/comments.css +++ b/assets/css/build/comments.css @@ -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; diff --git a/assets/css/build/comments.min.css b/assets/css/build/comments.min.css index 9f79cf75..6e152189 100644 --- a/assets/css/build/comments.min.css +++ b/assets/css/build/comments.min.css @@ -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: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{font-size:13px}.comt-tips-left .but svg,.comt-tips-left .but .fa{margin:0}.btn-input-expand{width:31px;padding:0;height:31px;line-height:31px}#postcomments .comment-header{font-size:14px}#postcomments .comt-meta{font-size:12px}#postcomments .comment .list-inline>li{padding:0}#postcomments .comment .list-inline>li+li{padding-left:10px}#postcomments .avatar-img{--this-size: 36px;margin-right:10px}#postcomments .commentlist>.comment>.list-inline .comment-footer{margin-left:45px;margin-top:-15px}#postcomments .children{margin-left:0}#postcomments .children .children{margin-left:13px}#postcomments .children .list-inline{padding:15px}#postcomments .post_ajax_loader .ml20{margin-left:5px}} +#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{font-size:13px}.comt-tips-left .but svg,.comt-tips-left .but .fa{margin:0}.btn-input-expand{width:31px;padding:0;height:31px;line-height:31px}#postcomments .comment-header{font-size:14px}#postcomments .comt-meta{font-size:12px}#postcomments .comment .list-inline>li{padding:0}#postcomments .comment .list-inline>li+li{padding-left:10px}#postcomments .avatar-img{--this-size: 36px;margin-right:10px}#postcomments .commentlist>.comment>.list-inline .comment-footer{margin-left:45px;margin-top:-15px}#postcomments .children{margin-left:0}#postcomments .children .children{margin-left:13px}#postcomments .children .list-inline{padding:15px}#postcomments .post_ajax_loader .ml20{margin-left:5px}} diff --git a/assets/css/frontend/comments/shell.css b/assets/css/frontend/comments/shell.css index 853f90c1..a2ac78c5 100644 --- a/assets/css/frontend/comments/shell.css +++ b/assets/css/frontend/comments/shell.css @@ -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; diff --git a/assets/js/comment-tools.js b/assets/js/comment-tools.js index fc37399f..4144d62e 100644 --- a/assets/js/comment-tools.js +++ b/assets/js/comment-tools.js @@ -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 '' + + '' + + '上传中' + + '' + + ''; + } + + 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 = '上传中'; + // 进度条与文案替换按钮内容;同时弹出参考主题的「正在处理」提示。 + 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); }; diff --git a/tests/widget-system/comment-image-upload-contract.test.cjs b/tests/widget-system/comment-image-upload-contract.test.cjs index bdad6270..e14c381f 100644 --- a/tests/widget-system/comment-image-upload-contract.test.cjs +++ b/tests/widget-system/comment-image-upload-contract.test.cjs @@ -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 条纹进度层铺满按钮', () => { + // 参考结构: + + // 内层 ,用 div 而非 span。 + assert.match( + tools, + /''[\s\S]{0,400}'<\/div><\/div>'/, + '上传中骨架必须复用参考主题的 miniupload-ing + Bootstrap 条纹进度层' + ); + assert.doesNotMatch(tools, /