This commit is contained in:
ken 2026-07-23 11:58:21 +08:00
parent 440ab19e02
commit 2df53550bf
4 changed files with 304 additions and 141 deletions

View File

@ -2552,6 +2552,276 @@ $(function() {
});
});
// 1. OrbitBar 基礎與搜尋選單邏輯
$(document).ready(function() {
const isEn = document.documentElement.lang === 'en';
const $orbitLabel = $('label[for="open-orbit-nav"]');
const $searchArea = $('.orbit-bar-search-sign-language');
const $firstInput = $('#q'); // 搜尋框通常是選單內第一個獲焦元素
// 初始化屬性
if (isEn) {
$orbitLabel.attr({ title: 'Site search and language menu', 'aria-label': 'Site search and language menu' });
} else {
$orbitLabel.attr({ title: '全站搜尋及語言切換選單', 'aria-label': '全站搜尋及語言切換選單' });
}
$orbitLabel.attr({ 'role': 'button', 'aria-haspopup': 'true', 'aria-expanded': 'false', 'tabindex': '0' });
// --- 【修正重點 1】處理 Label 的焦點與按鍵行為 ---
$orbitLabel.on('focusin', function(e) {
var relatedTarget = e.relatedTarget;
// 如果是從選單內部退回來的 (Shift+Tab)
if (relatedTarget && ($searchArea.find(relatedTarget).length > 0)) {
$searchArea.removeClass('show');
$(this).attr('aria-expanded', 'false');
} else {
// 正向進入
$searchArea.addClass('show');
$(this).attr('aria-expanded', 'true');
}
});
// 強制偵測:在 Label 上按下 Shift+Tab 代表要離開這整塊,立即收合
$orbitLabel.on('keydown', function(e) {
if (e.shiftKey && e.keyCode === 9) { // Shift + Tab
$searchArea.removeClass('show');
$searchArea.find('ul').removeClass('show');
$(this).attr('aria-expanded', 'false');
}
});
// --- 【修正重點 2】處理選單內第一個元素的 Shift+Tab ---
$firstInput.on('keydown', function(e) {
if (e.shiftKey && e.keyCode === 9) { // 在第一個輸入框按 Shift + Tab
// 讓它自然回到 LabelLabel 的 focusin 會接手處理收合
// 這裡不做額外動作,交給上面的 focusin 邏輯
}
});
// --- 【修正重點 3】處理離開大區塊往後 Tab的狀態清除 ---
$searchArea.on('focusout', function() {
var $thisArea = $(this);
setTimeout(function() {
if (!$thisArea.is(':focus-within') && !$(document.activeElement).is($orbitLabel)) {
$thisArea.removeClass('show');
$thisArea.find('ul').removeClass('show');
$orbitLabel.attr('aria-expanded', 'false');
$('#languagebutton').attr('aria-expanded', 'false');
}
}, 150);
});
// 點擊行為
$orbitLabel.on('click', function() {
var isOpen = $searchArea.hasClass('show');
$searchArea.toggleClass('show', !isOpen);
$(this).attr('aria-expanded', !isOpen);
});
// RWD 位置搬移
function moveSearch() {
if ($(window).width() < 767) {
$searchArea.insertAfter('label[for="open-orbit-nav"]');
} else {
$searchArea.appendTo('.orbit-bar-inner');
}
}
moveSearch();
$(window).resize(moveSearch);
});
// 2. 語言按鈕與手機版選單補強
$(function() {
function fixLanguageA11y() {
var isEn = document.documentElement.lang === 'en';
var correctTitle = isEn ? 'Open language menu' : '在本視窗開啟語言選單';
var $desktopBtn = $('#languagebutton');
var $langLi = $('#language-li');
var $langUl = $('#language-li ul');
// =============================================
// ✅ 新增 GN1210101E繁體中文 li 補上可聚焦 <a>
// 桌面版 + 手機版都處理
// =============================================
var $activeLis = $langUl.find('li.active')
.add($('#language-li-ul').find('li.active'));
$activeLis.each(function() {
var $li = $(this);
if ($li.find('a, button').length === 0) {
var activeText = $li.text().trim();
$li.html(
'<a href="javascript:;" ' +
'aria-current="true" ' +
'title="' + (isEn ? 'Current language' : '目前語言') + '" ' +
'tabindex="0">' +
activeText +
'</a>'
);
}
});
// =============================================
// Desktop 語言按鈕
// =============================================
if ($desktopBtn.length > 0) {
$desktopBtn.attr({
'aria-expanded': 'false',
'role': 'button',
'aria-haspopup': 'true',
'title': correctTitle
});
$desktopBtn.removeAttr('aria-label');
function openLangMenu() {
$langUl.addClass('show');
$desktopBtn.attr('aria-expanded', 'true');
$('.orbit-bar-search-sign-language').addClass('show');
}
function closeLangMenu() {
$langUl.removeClass('show');
$desktopBtn.attr('aria-expanded', 'false');
}
// 原有focus 展開
$desktopBtn.on('focus', function() {
openLangMenu();
});
// ✅ 新增 GN1210100EEnter / Space 切換、Escape 收合
$desktopBtn.on('keydown', function(e) {
if (e.which === 13 || e.which === 32) {
e.preventDefault();
$langUl.hasClass('show') ? closeLangMenu() : openLangMenu();
}
if (e.which === 27) {
closeLangMenu();
$desktopBtn.focus();
}
});
// 原有click 切換
$desktopBtn.on('click', function(e) {
e.preventDefault();
$langUl.hasClass('show') ? closeLangMenu() : openLangMenu();
});
// ✅ 新增:選單內 Escape 跳回按鈕
$langUl.find('a').on('keydown', function(e) {
if (e.which === 27) {
e.preventDefault();
closeLangMenu();
$desktopBtn.focus();
}
});
// 原有:焦點離開整個 language-li 時收合
$langLi.on('focusout', function() {
var $container = $(this);
setTimeout(function() {
if (!$container.is(':focus-within')) {
closeLangMenu();
}
}, 150);
});
}
// =============================================
// 手機版選單補強(原有邏輯完整保留)
// =============================================
var $mobileBtn = $('.mobile-button');
if ($mobileBtn.length > 0) {
$mobileBtn.attr({ 'role': 'button', 'tabindex': '0', 'aria-haspopup': 'true', 'aria-expanded': 'false' });
$mobileBtn.on('focus', function() {
$(this).closest('li').find('ul').addClass('show');
$(this).attr('aria-expanded', 'true');
});
$mobileBtn.on('keydown', function(e) {
if (e.which === 13 || e.which === 32) {
e.preventDefault();
var $ul = $(this).closest('li').find('ul');
$ul.toggleClass('show');
$(this).attr('aria-expanded', $ul.hasClass('show') ? 'true' : 'false');
}
});
$('#language-li-ul').on('focusout', function() {
var $container = $(this);
setTimeout(function() {
if (!$container.is(':focus-within')) {
$container.find('ul').removeClass('show');
$mobileBtn.attr('aria-expanded', 'false');
}
}, 150);
});
}
// =============================================
// 原有MutationObserver 強制鎖定 title
// =============================================
var target = document.getElementById('languagebutton');
if (target) {
var observer = new MutationObserver(function() {
if (target.getAttribute('title') !== correctTitle) {
target.setAttribute('title', correctTitle);
}
});
observer.observe(target, { attributes: true, attributeFilter: ['title'] });
}
}
setTimeout(fixLanguageA11y, 600);
});
// rwd左上選單無障礙
$(function() {
/**
* 修正當焦點離開整個區塊含語言選單最後一項關閉大選單
*/
function fixSearchMenuFocusOut() {
var $searchArea = $('.orbit-bar-search-sign-language');
var $orbitLabel = $('label[for="open-orbit-nav"]');
var $langBtn = $('#languagebutton');
// 使用 focusout 監聽整個搜尋/語言區域
$searchArea.on('focusout', function(e) {
// 關鍵:使用 setTimeout 讓 document.activeElement 抓到下一個獲焦元素
setTimeout(function() {
// 如果目前的焦點不在 $searchArea 裡面,也不是回到觸發的 $orbitLabel 上
if (!$searchArea.is(':focus-within') && !$(document.activeElement).is($orbitLabel)) {
// 1. 移除大區塊顯示
$searchArea.removeClass('show');
// 2. 移除子層語言選單顯示
$searchArea.find('ul').removeClass('show');
// 3. 狀態重置為「折疊」供語音報讀
$orbitLabel.attr('aria-expanded', 'false');
$langBtn.attr('aria-expanded', 'false');
}
}, 50);
});
// 桌面版 Language 按鈕特殊處理:焦點移入時
$langBtn.on('focus', function() {
// 確保父層搜尋區塊是顯示的 (針對從別處直接 tab 過來的情況)
$searchArea.addClass('show');
$(this).attr('aria-expanded', 'true');
});
// 針對手機版 mobile-button (span) 同理處理
$('.mobile-button').on('focusout', function() {
var $mobileParent = $('#language-li-ul');
setTimeout(function() {
if (!$mobileParent.is(':focus-within')) {
$mobileParent.find('ul').removeClass('show');
$('.mobile-button').attr('aria-expanded', 'false');
}
}, 50);
});
}
setTimeout(fixSearchMenuFocusOut, 600);
});
//萬用表格查詢按鈕翻中英
$(document).ready(function () {
const lang = $('html').attr('lang');

View File

@ -31,7 +31,7 @@ ul.button-mid{
}
}
.button-mid {
z-index: 100;
z-index: 199;
position: absolute;
width: 100%;
height: 0;

View File

@ -1764,7 +1764,7 @@ a.w-annc__a {
// Widget-6
.widget-announcement-6 {
.w-annc__postdate{
border: 2px solid #4d85b5;
border: 2px solid #2978bc;
border-radius: 0.5em;
display: block;
text-align: center;
@ -1774,14 +1774,14 @@ a.w-annc__a {
}
.w-annc__postdate-year{
display: block;
background: #4d85b5;
background: #2978bc;
padding: 0.2em;
color: #fff;
}
.w-annc__postdate-md{
display: block;
padding: 0.2em;
color: #4d85b5;
color: #2978bc;
}
.w-annc__category{
margin: 0px 0px 0px 0px;
@ -1847,7 +1847,7 @@ a.w-annc__a {
// Widget-7
.widget-announcement-7 {
.w-annc__postdate{
border: 2px solid #4d85b5;
border: 2px solid #2978bc;
border-radius: 0.5em;
display: block;
text-align: center;
@ -1857,14 +1857,14 @@ a.w-annc__a {
}
.w-annc__postdate-year{
display: block;
background: #4d85b5;
background: #2978bc;
padding: 0.2em;
color: #fff;
}
.w-annc__postdate-md{
display: block;
padding: 0.2em;
color: #4d85b5;
color: #2978bc;
}
.w-annc__category{
margin: 0px 0px 0px 0px;
@ -2004,7 +2004,7 @@ a.w-annc__a {
// Widget-10
.widget-announcement-10 {
.w-annc__postdate{
border: 2px solid #4d85b5;
border: 2px solid #2978bc;
border-radius: 0.5em;
display: block;
text-align: center;
@ -2014,14 +2014,14 @@ a.w-annc__a {
}
.w-annc__postdate-year{
display: block;
background: #4d85b5;
background: #2978bc;
padding: 0.2em;
color: #fff;
}
.w-annc__postdate-md{
display: block;
padding: 0.2em;
color: #4d85b5;
color: #2978bc;
}
.w-annc__item {
&:hover{
@ -2782,7 +2782,7 @@ table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before, tabl
}
}
.i-annc__postdate{
border: 2px solid #4d85b5;
border: 2px solid #2978bc;
border-radius: 0.5em;
display: block;
text-align: center;
@ -2792,14 +2792,14 @@ table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before, tabl
}
.i-annc__postdate-year{
display: block;
background: #4d85b5;
background: #2978bc;
padding: 0.2em;
color: #fff;
}
.i-annc__postdate-md{
display: block;
padding: 0.2em;
color: #4d85b5;
color: #2978bc;
}
.i-annc__item {
margin-bottom: 0;
@ -2834,7 +2834,7 @@ table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before, tabl
.index-announcement-3,
.index-announcement-4 {
.i-annc__postdate{
border: 2px solid #4d85b5;
border: 2px solid #2978bc;
border-radius: 0.5em;
display: block;
text-align: center;
@ -2844,14 +2844,14 @@ table.dataTable.dtr-inline.collapsed>tbody>tr.parent>td:first-child:before, tabl
}
.i-annc__postdate-year{
display: block;
background: #4d85b5;
background: #2978bc;
padding: 0.2em;
color: #fff;
}
.i-annc__postdate-md{
display: block;
padding: 0.2em;
color: #4d85b5;
color: #2978bc;
}
.i-annc__item {

View File

@ -21,7 +21,7 @@
data-cycle-title="{{title}}"
data-cycle-desc="{{context}}"
data-overlay-template="<h3>{{title}}</h3>{{desc}}"
data-target="{{target}}"
data-bs-target="{{target}}"
>
<a href="{{link}}" target="{{target}}" title="{{alt_title}}">
<img class="w-ba-banner__image banner-responsive" src="{{image_link}}" alt="{{alt_title}}">
@ -29,10 +29,7 @@
</div>
</div>
<div class="w-ad-banner__pager-2 w-ba-banner__caption banner-pager banner_caption_{{subpart-id}}" data-list="images" data-level="0">
<li><button title="Slide {{slide_number}}" aria-label="Pager"><span style="display: none;">Slide {{slide_number}}</span></button></li>
</div>
<ul class="w-ba-banner__pager-2 banner-pager banner_caption_{{subpart-id}}"></ul>
<ul class="controlplay" role="radiogroup" aria-label="播放控制選項">
<a role="radio" aria-checked="true" href="javascript:;" class="resume-slide active" title="繼續播放" aria-label="繼續播放" aria-live="assertive">
<i aria-hidden="true"></i>
@ -44,38 +41,11 @@
<p style="display: none;"><%= I18n.t("ad_banner.pause") %></p>
</a>
</ul>
<ul class="button-mid">
<i class="fa fa-angle-left prev-button" aria-hidden="true" title = "<%= (I18n.locale.to_s =="zh_tw") ? "上一張" : "prev" %>"></i>
<i class="fa fa-angle-right next-button" aria-hidden="true" title = "<%= (I18n.locale.to_s =="zh_tw") ? "下一張" : "next" %>"></i>
</ul>
<ul class="button-mid">
<i class="fa fa-angle-left prev-button" aria-label="<%= I18n.t("ad_banner.prev") %>"></i>
<i class="fa fa-angle-right next-button" aria-label="<%= I18n.t("ad_banner.next") %>"></i>
</ul>
</div>
<style>
.ba-banner-widget-2 {
position: relative;
overflow: hidden;
}
.ba-banner-widget-2 > .banner-bg-blur {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 0;
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
filter: blur(12px);
transform: scale(1.05);
opacity: 0.9;
pointer-events: none;
}
.ba-banner-widget-2 > .banner-bg-blur:not(.has-bg) {
display: none;
}
</style>
<script>
var flag = 1;
$('.pause-slide').click(function(){
@ -91,96 +61,19 @@
$('.prev-button').off('click').on('click',function(){
$(this).parent("ul").parent('.w-ba-banner').find(".cycle-slideshow").cycle("prev");
});
/* 修正點:處理 Pager 無障礙朗讀文字 */
$('.cycle-slideshow').on('cycle-post-initialize', function(event, optionHash) {
var $container = $(this).closest('.w-ba-banner');
var $slides = $(this).find('.w-ba-banner__slide');
var $pagerButtons = $container.find(".banner-pager button");
$(document).ready(function() {
function ensureBgLayer($widget) {
var $bg = $widget.children('.banner-bg-blur');
if ($bg.length === 0) {
$bg = $('<div class="banner-bg-blur" aria-hidden="true"></div>');
$widget.prepend($bg);
}
return $bg;
}
function getActiveSlide($widget) {
// 明確以 cycle-slide-active 為優先
var $active = $widget.find('.w-ba-banner__slide.cycle-slide-active').first();
if (!$active.length) {
// fallback找 active 類或 visible
$active = $widget.find('.w-ba-banner__slide.active, .w-ba-banner__slide:visible').first();
}
return $active.length ? $active : null;
}
function getSlideImgSrc($slide) {
if (!$slide) return null;
var $img = $slide.find('img.w-ba-banner__image').first();
if (!$img.length) return null;
return $img.attr('src') || $img.attr('data-src') || null;
}
function setBgImage($bg, src) {
if (!src) {
$bg.removeClass('has-bg').css('background-image', '');
return;
}
// preload 圖片,確定可用再設定
var img = new Image();
img.onload = function() {
$bg.css('background-image', 'url("' + src + '")').addClass('has-bg');
};
img.onerror = function() {
// 失敗時移除
$bg.removeClass('has-bg').css('background-image', '');
};
img.src = src;
}
function updateWidgetBg($widget) {
var $bg = ensureBgLayer($widget);
var $active = getActiveSlide($widget);
var src = $active ? getSlideImgSrc($active) : null;
setBgImage($bg, src);
}
// 初始化每個 widget
$('.ba-banner-widget-2').each(function() {
var $widget = $(this);
if ($widget.css('position') === 'static') {
$widget.css('position', 'relative');
}
ensureBgLayer($widget);
updateWidgetBg($widget);
// 監聽常見輪播事件Cycle2 / Slick / Owl
$widget.on('cycle-after cycle-after.fallback afterChange changed.owl.carousel slide.bs.carousel', function() {
// 延遲小幅等待 class 變更
setTimeout(function() { updateWidgetBg($widget); }, 30);
});
// pager / prev / next 互動也作為保險
$widget.find('.prev-button, .next-button, .banner-pager, .w-ba-banner__pager-2').on('click keydown', function() {
setTimeout(function() { updateWidgetBg($widget); }, 50);
});
// MutationObserver監控 class 或子節點改變(當 plugin 只改 class 時可捕捉)
if (window.MutationObserver) {
var mo = new MutationObserver(function(muts) {
var needUpdate = false;
muts.forEach(function(m) {
if (m.type === 'attributes' && m.attributeName === 'class') needUpdate = true;
if (m.type === 'childList') needUpdate = true;
});
if (needUpdate) {
setTimeout(function() { updateWidgetBg($widget); }, 30);
}
$pagerButtons.each(function(index) {
var slideTitle = $slides.eq(index).data('cycle-title') || "";
var ariaLabel = "第 " + (index + 1) + " 張投影片 " + slideTitle;
$(this).attr({
"aria-label": ariaLabel,
"title": ariaLabel
});
mo.observe($widget[0], { childList: true, subtree: true, attributes: true, attributeFilter: ['class', 'src', 'data-src'] });
}
});
});
});
</script>