This commit is contained in:
ken 2026-09-02 20:20:30 +08:00
parent 335f98436c
commit 26d7c5eddf
8 changed files with 221 additions and 55 deletions

View File

@ -533,20 +533,28 @@ $(document).ready(function () {
}); });
//播放驗證碼語音 //播放驗證碼語音
$(function () { $(function () {
$('.ask-question') var pageLang = ($('html').attr('lang') || 'zh-Hant').toLowerCase();
.find('.controls button.fas.fa-volume-up') var isEn = pageLang.startsWith('en');
.each(function () { var label = isEn ? 'Play Captcha Voice' : '播放驗證碼語音';
const $btn = $(this);
// 已經補過就不重複處理 $('.ask-question')
if ($btn.attr('aria-label')) return; .find('.controls button.fas.fa-volume-up')
.each(function () {
var $btn = $(this);
$btn.attr({ $btn.attr({
'aria-label': '播放驗證碼語音', 'aria-label': label,
'aria-controls': 'captcha_audio', 'title': label,
'role': 'button' 'aria-controls': 'captcha_audio',
}); 'role': 'button'
}); });
// ✅ 同步更新 sr-only 文字(若有)
var $sr = $btn.find('.sr-only');
if ($sr.length > 0) {
$sr.text(label);
}
});
}); });
//刪除td的id //刪除td的id
@ -3429,6 +3437,50 @@ $(document).ready(function () {
// 比 fixAccessibilityAll 的 800ms 晚,確保最後執行 // 比 fixAccessibilityAll 的 800ms 晚,確保最後執行
setTimeout(fixGalleryViewLinkA11y, 2000); setTimeout(fixGalleryViewLinkA11y, 2000);
}); });
//No History Records
function fixTicketHistoryStatusA11y() {
var $form = $('#check_history_form');
if (!$form.length) return;
// 建立 role=status 播報區(若不存在)
if (!$('#ticket-history-result-status').length) {
$form.after('<div id="ticket-history-result-status" role="status" aria-live="polite" aria-atomic="true" class="visually-hidden"></div>');
}
var $statusBox = $('#ticket-history-result-status');
// MutationObserver 監聽 #history_area 的變化
var $historyArea = $('#history_area');
if (!$historyArea.length) return;
var observer = new MutationObserver(function () {
var $noRecord = $historyArea.find('span.translation_missing');
if ($noRecord.length) {
// 取得文字(顯示文字或 title 屬性)
var msg = $noRecord.text().trim() || $noRecord.attr('title') || 'No History Records';
// 把訊息寫入 role=status 區塊觸發播報
$statusBox.text('').text(msg);
// 同時在 span 上加 role=status(雙保險)
if ($noRecord.attr('role') !== 'status') {
$noRecord.attr('role', 'status').attr('aria-live', 'polite').attr('aria-atomic', 'true');
}
} else {
// 有查到結果時清空播報區
$statusBox.text('');
}
});
observer.observe($historyArea[0], {
childList: true,
subtree: true
});
}
$(document).ready(function () {
setTimeout(fixTicketHistoryStatusA11y, 500);
});
//會員 //會員
$(function() { $(function() {
function fixMemberAcademicLinkA11y() { function fixMemberAcademicLinkA11y() {

View File

@ -214,6 +214,10 @@ img{
// overflow-x: auto; // overflow-x: auto;
// } // }
// } // }
*[data-pp]>.editmode-ps>a, .admin-subpart-area .content>.editmode-ps>a{ input[type=checkbox]:focus {
position: !important; outline: 0.3125em auto -webkit-focus-ring-color!important;
}
button.fas.fa-volume-up:focus {
outline: 0.3125em auto -webkit-focus-ring-color!important;
outline-offset: -0.125em!important;
} }

View File

@ -1,6 +1,13 @@
@charset "utf-8"; @charset "utf-8";
@import "../initial"; @import "../initial";
.ask-question-form .form-actions input {
float: none !important;
margin-right: 1em;
}
.ask-question .form-horizontal .form-actions {
text-align: end!important;
}
.line-it-button{ .line-it-button{
.label{ .label{
color: #333!important; color: #333!important;

View File

@ -26,8 +26,7 @@
</div> </div>
<div class="i-archive-files-list col-sm-9" data-list="files" data-level="2"> <div class="i-archive-files-list col-sm-9" data-list="files" data-level="2">
<dd> <dd>
<a href="{{file-url}}" class="i-archive-files-item" target="{{target}}" title="{{file-name}}">{{file-name}}</a> <a href="{{file-url}}" class="i-archive-files-item" target="{{target}}" title="{{file-name}}">{{file-name}}<span class="label label-primary">{{file-type}}</span></a>
<a href="{{file-url}}" class="i-archive-files-item" target="_blank" data-toggle="tooltip" data-placement="bottom" title="{{file-name}}"><span class="label label-primary">{{file-type}}</span></a>
</dd> </dd>
</div> </div>
</div> </div>

View File

@ -8,9 +8,9 @@
<div class="i-member-item row"> <div class="i-member-item row">
<div class="i-member-item-inner clearfix"> <div class="i-member-item-inner clearfix">
<div class="i-member-pic-wrap col-sm-3"> <div class="i-member-pic-wrap col-sm-3">
<a href="{{link_to_show}}" title="{{name}}">
<img class="i-member-pic img-thumbnail" src="{{image}}" title="{{name}}"> <img class="i-member-pic img-thumbnail" src="{{image}}" alt="{{name}}">
</a>
</div> </div>
<div class="i-member-profile-data-wrap col-sm-9"> <div class="i-member-profile-data-wrap col-sm-9">
<ul class="i-member-profile-list" data-list="profile_data" data-level="3"> <ul class="i-member-profile-list" data-list="profile_data" data-level="3">

View File

@ -9,7 +9,7 @@
<div class="i-member-item-inner clearfix"> <div class="i-member-item-inner clearfix">
<div class="i-member-pic-wrap col-sm-12"> <div class="i-member-pic-wrap col-sm-12">
<a href="{{link_to_show}}" title="{{name}}"> <a href="{{link_to_show}}" title="{{name}}">
<img class="i-member-pic img-thumbnail" src="{{image}}" title="{{name}}"> <img class="i-member-pic img-thumbnail" src="{{image}}" alt="{{name}}">
</a> </a>
</div> </div>
<div class="i-member-profile-data-wrap col-sm-12"> <div class="i-member-profile-data-wrap col-sm-12">

View File

@ -1,40 +1,143 @@
<div class="marquee-1" module="text_marquee" data-ps=""> <div class="marquee-1" module="text_marquee" data-ps="">
<h3 class="marquee-title"> <div class="marquee-1-controls">
<span>{{widget-title}}</span> <h3 class="marquee-title">
</h3> <span>{{widget-title}}</span>
<ul class="marquee" data-level="0" data-list="texts"> </h3>
<li>{{content}}</li> <ul class="controlplay" role="radiogroup" aria-label="播放控制選項">
</ul> <a role="radio" aria-checked="true" href="javascript:;" class="resume-slide active" title="繼續播放" aria-label="繼續播放" aria-live="assertive">
<i aria-hidden="true"></i>
</a>
<a role="radio" aria-checked="false" href="javascript:;" class="pause-slide" title="暫停播放" aria-label="暫停播放" aria-live="assertive">
<i aria-hidden="true"></i>
</a>
</ul>
</div>
<ul class="marquee" data-level="0" data-list="texts">
<li>{{content}}</li>
</ul>
</div> </div>
<style>
.marquee-1 .controlplay {
display: flex;
justify-content: flex-end;
align-items: center;
list-style: none;
margin: 0 0 6px 0;
padding: 0;
gap: 4px;
top: 1em;
}
.marquee-1 .controlplay a {
display: inline-block;
margin-right: 0.25em;
cursor: pointer;
padding: 5px 10px;
border: 1px solid rgba(255, 255, 255, 0.5);
background: rgba(0, 0, 0, 0.2);
}
.marquee-1 .controlplay a i {
font-family: FontAwesome;
position: relative;
font-size: 1rem;
line-height: 1;
color: #FFF;
vertical-align: middle;
font-style: unset;
}
.marquee-1 .controlplay a:hover {
border-color: #888;
}
.marquee-1 .controlplay a:focus {
outline: 2px solid #005fcc;
outline-offset: 2px;
}
.marquee-1 .controlplay .resume-slide i::before {
content: "\f04b";
}
.marquee-1 .controlplay .pause-slide i {
display: inline-flex;
gap: 3px;
align-items: center;
}
.marquee-1 .controlplay .pause-slide i::before {
content: "\f04c";
}
.marquee-1 .controlplay .resume-slide.active i {
color: #32D9C3;
}
.marquee-1 .controlplay .pause-slide.active i {
color: #ff4500;
}
</style>
<script type="text/javascript"> <script type="text/javascript">
(function(){ (function(){
var main_div = $("div[data-subpart-id={{subpart-id}}]"), var main_div = $("div[data-subpart-id={{subpart-id}}]");
total_texts = main_div.find("ul li").length - 1, var $resumeBtn = main_div.find(".resume-slide");
current_text = 0, var $pauseBtn = main_div.find(".pause-slide");
last_text = 0; var total_texts = main_div.find("ul li").length - 1;
var current_text = 0;
var last_text = 0;
var isPaused = false;
var timer = null;
main_div.find("ul li").hide(); main_div.find("ul li").hide();
var textTransform = function(){
current_text++;
current_text = (current_text > total_texts ? 0 : current_text);
last_text = (current_text == 0 ? total_texts : current_text - 1);
speed = $('.marquee > li > a').eq(current_text).attr('speed');
main_div.find("ul li").eq(last_text).slideUp(500);
main_div.find("ul li").eq(current_text).slideDown(500);
if(total_texts > 0){
setTimeout(textTransform,speed);
}
}
setTimeout(textTransform,500);
})();
</script>
<script type="text/javascript">
(function(){
var main_div = $("div[data-subpart-id"{{subpart-id}})
}
</script>
function textTransform() {
if (isPaused) return;
current_text++;
current_text = (current_text > total_texts ? 0 : current_text);
last_text = (current_text == 0 ? total_texts : current_text - 1);
var speed = main_div.find('.marquee > li > a').eq(current_text).attr('speed');
main_div.find("ul li").eq(last_text).slideUp(500);
main_div.find("ul li").eq(current_text).slideDown(500);
if (total_texts > 0) {
timer = setTimeout(textTransform, speed);
}
}
function pauseAll() {
isPaused = true;
clearTimeout(timer);
$pauseBtn.attr('aria-checked', 'true').addClass('active');
$resumeBtn.attr('aria-checked', 'false').removeClass('active');
}
function resumeAll() {
isPaused = false;
$resumeBtn.attr('aria-checked', 'true').addClass('active');
$pauseBtn.attr('aria-checked', 'false').removeClass('active');
var speed = main_div.find('.marquee > li > a').eq(current_text).attr('speed') || 500;
timer = setTimeout(textTransform, speed);
}
$resumeBtn.on('click', function(e) {
e.preventDefault();
if (isPaused) resumeAll();
});
$pauseBtn.on('click', function(e) {
e.preventDefault();
if (!isPaused) pauseAll();
});
$resumeBtn.addClass('active').attr('aria-checked', 'true');
$pauseBtn.attr('aria-checked', 'false');
timer = setTimeout(textTransform, 500);
})();
</script>

View File

@ -9,11 +9,12 @@
<img src="{{img_src}}" alt="{{img_description}}"> <img src="{{img_src}}" alt="{{img_description}}">
</div> </div>
<div class="widget-content-title"> <div class="widget-content-title">
<a class="" href="{{link_to_show}}" target="{{target}}" title="{{title_text}}">{{title}}</a> <span>{{title}}</span>
<span data-list="statuses" data-level="1"> <span data-list="statuses" data-level="1">
<span class="label status {{status-class}}">{{status}}</span> <span class="label status {{status-class}}">{{status}}</span>
</span> </span>
</div> </div>
</a>
</li> </li>
</ul> </ul>
</div> </div>