diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js
index 348c0c7..bff3fcc 100644
--- a/assets/javascripts/app.js
+++ b/assets/javascripts/app.js
@@ -737,20 +737,20 @@
$(this).attr("style", newStyle);
}
});
- //表格scope
- $("table").each(function() {
- $(this).find("tr").each(function(rowIndex) {
- $(this).find("th").each(function(colIndex) {
- if (rowIndex === 0) {
- // 第一列的 th,適用於該欄
- $(this).attr("scope", "col");
- } else if (colIndex === 0) {
- // 其他列的第一個 th,適用於該行
- $(this).attr("scope", "row");
- }
- });
- });
- });
+ // //表格scope
+ // $("table").each(function() {
+ // $(this).find("tr").each(function(rowIndex) {
+ // $(this).find("th").each(function(colIndex) {
+ // if (rowIndex === 0) {
+ // // 第一列的 th,適用於該欄
+ // $(this).attr("scope", "col");
+ // } else if (colIndex === 0) {
+ // // 其他列的第一個 th,適用於該行
+ // $(this).attr("scope", "row");
+ // }
+ // });
+ // });
+ // });
$(".banner-pager button").addClass('banner-pagerbtn');
$(".banner-pager button").attr("type","button");
$(".banner-pager button").append('下一張');
@@ -794,13 +794,14 @@
$(document).ready(function() {
removeEmptyTitles();
});
- $(".w-annc__img-wrap a").each(function () {
- var $this = $(this);
- // 確保 內沒有文字節點 (避免重複添加)
- if ($this.text().trim() === "") {
- $this.append('公告圖片');
- }
- });
+
+ // $(".w-annc__img-wrap a").each(function () {
+ // var $this = $(this);
+ // // 確保 內沒有文字節點 (避免重複添加)
+ // if ($this.text().trim() === "") {
+ // $this.append('公告圖片');
+ // }
+ // });
$(".widget-link__widget-title").each(function () {
if ($(this).text().trim() === "") {
$(this).append('公告標題');
@@ -858,264 +859,307 @@
/**
* 圖片無障礙 AA 級補強 (人工檢測優化版)
*/
- function fixAccessibilityAll() {
- // --- 0. 環境與語言偵測 ---
- var urlParams = new URLSearchParams(window.location.search);
- var isEditMode = urlParams.get('editmode') === 'on';
-
- var pageLang = $('html').attr('lang') || 'zh-Hant';
- var isEn = pageLang.toLowerCase().startsWith('en');
-
- var i18n = {
- langBtn: isEn ? 'Open language menu in this window' : '在本視窗開啟語言選單',
- newWin: isEn ? '(Open in new window)' : '(在新視窗開啟)',
- selfWin: isEn ? '(Open in this window)' : '(在本視窗開啟)',
- link: isEn ? 'Link' : '連結',
- openImg: isEn ? 'Open image' : '開啟圖片內容'
- };
-
- // --- Part 1: 語言選單修正 ---
- var $langBtn = $('#languagebutton');
- if ($langBtn.length > 0) {
- $langBtn.attr('title', i18n.langBtn);
- $langBtn.removeAttr('aria-label');
- }
-
- // --- Part 2: 全站連結與圖片邏輯處理 ---
- $('a').each(function() {
- var $a = $(this);
- var href = ($a.attr('href') || '').toLowerCase();
- if (!href || href.startsWith('javascript:')) return;
-
- // 清理 與 空白
- var linkText = $a.text().replace(/\u00a0/g, '').trim();
- var $img = $a.find('img');
- var currentTitle = ($a.attr('title') || '').trim();
+ function fixImageAccessibility() {
+ $('img').each(function() {
+ var $img = $(this);
+ var $parentA = $img.closest('a'); // 取得父層連結
+ var currentAlt = ($img.attr('alt') || '').trim();
+ var currentTitle = ($img.attr('title') || '').trim();
- // --- 【修正:隱藏空連結】 ---
- if (!isEditMode && linkText === "" && $img.length === 0) {
- $a.hide();
+ // 判定該連結是否「僅靠圖片傳達目的」(連結內無文字)
+ var isLinkImage = $parentA.length > 0 && $parentA.text().replace(/\u00a0/g, '').trim() === "";
+
+ // --- 1. 處理「裝飾性圖片」標註 ---
+ if (currentAlt === "announcement image" || currentAlt === "裝飾圖片" || currentTitle === "裝飾圖片" || currentAlt === "這是一張圖片" || currentTitle === "這是一張圖片") {
+ $img.attr('alt', '');
+ $img.removeAttr('title');
return;
}
- // A. 視窗動作規範
- var isNewWindow = ($a.attr('target') === '_blank');
- var windowTask = isNewWindow ? i18n.newWin : i18n.selfWin;
-
- // B. 偵測檔案類型
- var fileExt = "";
- var fileMatches = href.match(/\.(pdf|doc|docx|xls|xlsx|ppt|pptx|odt|ods|odp|zip|rar|jpg|png|csv)$/);
- if (fileMatches) {
- fileExt = fileMatches[1].toLowerCase();
+ // --- 2. 解決【alt 與 title 相同】的問題 ---
+ if (currentAlt !== '' && currentAlt === currentTitle) {
+ $img.removeAttr('title');
+ currentTitle = '';
}
- // C. 智慧修正標題 (移除冗餘資訊)
- var hasBadSymbol = currentTitle.includes('()') ||
- currentTitle.includes('另開新視窗') ||
- currentTitle.includes('Open in new window') ||
- currentTitle.includes('/uploads/'); // 移除包含路徑的標題
+ // --- 3. 處理「缺失 alt」或「空的 alt」補強邏輯 ---
+ // 修改點:若是具有連結用途的圖片,alt 不可為空
+ if (currentAlt === '') {
+ let finalAlt = "";
- // D. 處理【HM1240400C】:圖片與文字毗鄰時,替代文字只能有一份
- // 判斷方式:連結內有圖片,且有文字內容(含隱藏文字)
- if ($img.length > 0 && linkText !== "") {
- // 1. 強制圖片設為裝飾性 (符合規範:鏈結文字只能有一份)
- $img.attr('alt', '');
-
- // 2. 針對「視覺隱藏但存在於 DOM」的文字 (如 display:none)
- var $hiddenSpans = $a.find('span').filter(function() {
- return $(this).css('display') === 'none' || $(this).attr('style')?.includes('display: none');
- });
-
- if ($hiddenSpans.length > 0) {
- $hiddenSpans.each(function() {
- var $span = $(this);
- // 如果隱藏文字包含檔案路徑,優化為有意義的文字
- if ($span.text().includes('/uploads/')) {
- $span.text(i18n.openImg);
- }
- // 將 display:none 轉為「視覺隱藏、機器可讀」樣式,確保讀屏器可讀取
- $span.css({
- 'display': 'inline-block',
- 'position': 'absolute',
- 'width': '1px',
- 'height': '1px',
- 'padding': '0',
- 'margin': '-1px',
- 'overflow': 'hidden',
- 'clip': 'rect(0, 0, 0, 0)',
- 'white-space': 'nowrap',
- 'border': '0'
- });
- });
- }
- }
-
- // E. 重新計算標題與替代文字 (針對不同情境)
- if (linkText === "" && $img.length > 0) {
- // 情境:純圖片連結
- var rawAlt = ($img.attr('alt') || '').trim();
- var forbidden = ['這是一張圖片', '圖片', 'image', 'photo', '圖', ''];
- var imgAlt = forbidden.some(function(txt) { return rawAlt.toLowerCase() === txt; })
- ? ($a.attr('aria-label') || i18n.link) : rawAlt;
+ // A. 優先嘗試從父層 () 的 title 抓取
+ var parentATitle = $parentA.attr('title');
- var fileInfo = fileExt ? '[' + fileExt.toUpperCase() + '] ' : '';
- $a.attr('title', (fileInfo + imgAlt + " " + windowTask).trim());
- $img.attr('alt', imgAlt);
- }
- else if (linkText !== "") {
- // 情境:有文字連結 (無論文字是可見還是透過 Part D 視覺隱藏)
- if (fileExt !== "" || hasBadSymbol || currentTitle === "" || currentTitle.includes('/uploads/')) {
- if (fileExt !== "") {
- $a.attr('title', linkText + " ." + fileExt + " " + windowTask);
- } else if (linkText.length <= 8) {
- $a.attr('title', linkText + " " + windowTask);
- } else {
- $a.attr('title', windowTask);
- }
+ // B. 嘗試抓取同區域內的標題文字
+ var nearbyTitle = $parentA.find('h1, h2, h3, h4, h5, h6').first().text().trim();
+
+ if (parentATitle && parentATitle.trim() !== '') {
+ // 移除 title 內的視窗提示字眼,只取純文字作為 alt
+ finalAlt = parentATitle.replace(/\(在本視窗開啟\)|\(在新視窗開啟\)/g, '').trim();
+ } else if (nearbyTitle !== '') {
+ finalAlt = nearbyTitle;
+ } else if (isLinkImage) {
+ // 如果是連結圖片且都抓不到文字,給予預設值「連結」避免檢測失敗
+ finalAlt = "連結";
+ }
+
+ $img.attr('alt', finalAlt);
+
+ // --- 4. 二次清理 ---
+ if (currentTitle !== '' && currentTitle === finalAlt) {
+ $img.removeAttr('title');
}
}
-
- // F. 最終清理:移除冗餘 label
- $a.removeAttr('aria-label');
});
}
- // 延遲執行確保 DOM 內容(如圖片路徑)載入完成
- setTimeout(function() {
- fixAccessibilityAll();
- }, 800);
+ setTimeout(fixImageAccessibility, 500);
});
- // 有連結目的之所有a標籤的無障礙處理
- $(function() {
- /**
- * 全站無障礙 AA 級補強 (多語系偵測版)
- */
- function fixAccessibilityAll() {
- // --- 0. 網址參數判斷 ---
- var urlParams = new URLSearchParams(window.location.search);
- var isEditMode = urlParams.get('editmode') === 'on';
- var pageLang = $('html').attr('lang') || 'zh-Hant';
- var isEn = pageLang.toLowerCase().startsWith('en');
+// 有連結目的之所有a標籤的無障礙處理
+$(function() {
+ // Bootstrap 會把原始 title 搬到 data-bs-original-title,先還原回來
+ $('a[data-bs-original-title]').each(function() {
+ var $a = $(this);
+ var originalTitle = $a.attr('data-bs-original-title');
+ if (originalTitle && originalTitle.trim() !== '') {
+ $a.attr('title', originalTitle);
+ }
+ });
- var i18n = {
- langBtn: isEn ? 'Open language menu in this window' : '在本視窗開啟語言選單',
- newWin: isEn ? '(Open in new window)' : '(在新視窗開啟)',
- selfWin: isEn ? '(Open in this window)' : '(在本視窗開啟)',
- link: isEn ? 'Link' : '連結'
- };
+ /**
+ * 全站無障礙 AA 級補強 (整合 HM1240400C 與 HM1240401C 規範)
+ */
+ function fixAccessibilityAll() {
+ // --- 0. 環境與語言偵測 ---
+ //1200ms 後執行(確保所有其他 function 執行完畢後才處理)
+ //Part 1:修正語言選單按鈕
+ //Part 2:掃描所有
+ //├─ 排除 navbar-brand、javascript: 連結
+ //├─ 空連結 → 隱藏
+ //├─ 文字是路徑/空 → 補隱藏 span
+ //├─ 圖片+文字共存 → 圖片 alt 清空
+ //├─ 無 title → 自動產出 title
+ //├─ 有 title 但與連結文字或圖片 alt 重複 → 只保留開窗提示
+ //├─ 有 title 出現空括號 () → 清除並補上正確開窗提示
+ //└─ 移除 aria-label
+ var urlParams = new URLSearchParams(window.location.search);
+ var isEditMode = urlParams.get('editmode') === 'on';
- // --- Part 1: 語言選單修正 ---
- var $langBtn = $('#languagebutton');
- if ($langBtn.length > 0) {
- $langBtn.attr('title', i18n.langBtn);
- $langBtn.removeAttr('aria-label');
+ var pageLang = $('html').attr('lang') || 'zh-Hant';
+ var isEn = pageLang.toLowerCase().startsWith('en');
+
+ var i18n = {
+ langBtn: isEn ? 'Open language menu in this window' : '在本視窗開啟語言選單',
+ newWin: isEn ? 'Open in new window' : '在新視窗開啟',
+ selfWin: isEn ? 'Open in this window' : '在本視窗開啟',
+ link: isEn ? 'Link' : '連結',
+ openImg: isEn ? 'Open image' : '開啟圖片內容',
+ sort: isEn ? 'Sort' : '排序'
+ };
+
+ // --- Part 1: 語言選單修正 ---
+ var $langBtn = $('#languagebutton');
+ if ($langBtn.length > 0) {
+ $langBtn.attr('title', i18n.langBtn);
+ $langBtn.removeAttr('aria-label');
+ }
+
+ // --- Part 2: 全站連結與圖片邏輯處理 ---
+ $('a').each(function() {
+ var $a = $(this);
+
+ // 【條件 1:排除特定 class】
+ if ($a.hasClass('navbar-brand')) {
+ return;
+ }
+
+ var href = ($a.attr('href') || '').toLowerCase();
+ if (!href || href.startsWith('javascript:')) return;
+
+ // --- 關鍵修正:先偵測是否有原始 title ---
+ var rawTitleAttr = $a.attr('title');
+ var hasOriginalTitle = (typeof rawTitleAttr !== 'undefined' && rawTitleAttr !== false && rawTitleAttr.trim() !== "");
+
+ // 清理 與 空白
+ var linkText = $a.text().replace(/\u00a0/g, '').trim();
+ var $img = $a.find('img');
+ var $icons = $a.find('i, svg');
+ var currentTitle = ($a.attr('title') || '').trim();
+
+ // ✅ 在 D 區塊清空 alt 之前,先記錄圖片原始 alt
+ var imgAltOriginal = $img.length > 0 ? ($img.attr('alt') || '').trim() : '';
+
+ // --- 【修正 1:隱藏空連結】 ---
+ if (!isEditMode && linkText === "" && $img.length === 0 && $icons.length === 0) {
+ $a.hide();
+ return;
+ }
+
+ // --- 【修正 2:文字語意防禦】 ---
+ if ((linkText === "" || linkText.startsWith('/') || linkText.includes('?')) && $img.length === 0 && $icons.length === 0) {
+ var accessibleText = i18n.link;
+ if (href.includes('sort')) {
+ accessibleText = i18n.sort;
+ }
+
+ var $span = $a.find('span');
+ if ($span.length > 0) {
+ $span.text(accessibleText);
+ } else {
+ $a.append('' + accessibleText + '');
+ $span = $a.find('span').last();
}
- // --- Part 2: 全站連結處理 ---
- $('a').each(function() {
- var $a = $(this);
- var href = ($a.attr('href') || '').toLowerCase();
- if (!href || href.startsWith('javascript:')) return;
-
- // 清理 與 空白
- var linkText = $a.text().replace(/\u00a0/g, '').trim();
- var $img = $a.find('img');
- var currentTitle = ($a.attr('title') || '').trim();
-
- // --- 【新增修正:隱藏空連結】 ---
- // 若網址沒有 editmode=on 時,判定 a 裡面文字為空且沒有圖片,則隱藏
- if (!isEditMode && linkText === "" && $img.length === 0) {
- $a.hide();
- return; // 跳過後續處理
- }
-
- // A. 視窗動作規範
- var isNewWindow = ($a.attr('target') === '_blank');
- var windowTask = isNewWindow ? i18n.newWin : i18n.selfWin;
-
- // B. 偵測檔案類型
- var fileExt = "";
- var fileMatches = href.match(/\.(pdf|doc|docx|xls|xlsx|ppt|pptx|odt|ods|odp|zip|rar|jpg|png|csv)$/);
- if (fileMatches) {
- fileExt = fileMatches[1].toLowerCase();
- }
-
- // C. 智慧修正與標題補充
- var hasBadSymbol = currentTitle.includes('()') ||
- currentTitle.includes('另開新視窗') ||
- currentTitle.includes('Open in new window');
-
- if (linkText === "" && $img.length > 0) {
- // 【純圖片連結】替代文字邏輯
- var rawAlt = ($img.attr('alt') || '').trim();
- var forbidden = ['這是一張圖片', '圖片', 'image', 'photo', '圖', ''];
- var imgAlt = forbidden.some(function(txt) { return rawAlt.toLowerCase() === txt; })
- ? ($a.attr('aria-label') || i18n.link) : rawAlt;
-
- var fileInfo = fileExt ? '[' + fileExt.toUpperCase() + '] ' : '';
-
- // 確保具備標題與圖片 alt
- $a.attr('title', (fileInfo + imgAlt + " " + windowTask).trim());
- $img.attr('alt', imgAlt);
- }
- else if (linkText !== "") {
- // 【有文字連結】
- if (fileExt !== "" || hasBadSymbol || currentTitle === "") {
- var isTag = $a.hasClass('label') || $a.hasClass('tag') || $a.find('[class*="tag"]').length > 0;
-
- if (fileExt !== "") {
- $a.attr('title', linkText + " ." + fileExt + " " + windowTask);
- } else if (linkText.length <= 6 || isTag) {
- $a.attr('title', linkText + " " + windowTask);
- } else {
- $a.attr('title', windowTask);
- }
- }
- }
-
- // --- 修正後的 Part D 最終清理 ---
- $a.removeAttr('aria-label');
-
- // 只有當「真正可見的文字」存在時,才將圖片設為裝飾性
- // 使用 clone() 移除隱藏元件後再計算文字,確保準確度
- var visibleText = $a.clone().find(':hidden, style, script').remove().end().text().replace(/\u00a0/g, '').trim();
-
- if (visibleText !== "" && $img.length > 0) {
- $img.attr('alt', '');
- } else {
- // 如果文字是隱藏的 (如你的範例),則必須保留或補強圖片 alt
- var rawAlt = ($img.attr('alt') || '').trim();
- if (rawAlt === "") {
- // 如果連圖片 alt 都沒寫,就從 a 的 title 抓
- var cleanTitle = currentTitle.replace(/\(在本視窗開啟\)|\(在新視窗開啟\)/g, '').trim();
- $img.attr('alt', cleanTitle || i18n.link);
- }
- }
+ $span.css({
+ 'display': 'inline-block', 'position': 'absolute', 'width': '1px', 'height': '1px',
+ 'padding': '0', 'margin': '-1px', 'overflow': 'hidden', 'clip': 'rect(0, 0, 0, 0)',
+ 'white-space': 'nowrap', 'border': '0'
});
+ linkText = accessibleText;
}
- setTimeout(function() {
- fixAccessibilityAll();
- }, 600);
+ // A. 視窗動作規範
+ var isNewWindow = ($a.attr('target') === '_blank');
+ var windowTask = isNewWindow ? i18n.newWin : i18n.selfWin;
+
+ // B. 偵測檔案類型
+ var fileExt = "";
+ var fileMatches = href.match(/\.(pdf|doc|docx|xls|xlsx|ppt|pptx|odt|ods|odp|zip|rar|jpg|png|csv)$/);
+ if (fileMatches) {
+ fileExt = fileMatches[1].toLowerCase();
+ }
+
+ // C. 智慧修正標題判斷
+ var hasBadSymbol = currentTitle.includes('()') ||
+ currentTitle.includes('Open in new window') ||
+ currentTitle.includes('/uploads/');
+
+ if (currentTitle.startsWith('/') || currentTitle.includes('?')) {
+ currentTitle = "";
+ }
+
+ // D. 處理【HM1240400C】:圖片與文字毗鄰時,替代文字只能有一份
+ if (($img.length > 0 || $icons.length > 0) && linkText !== "") {
+ if ($img.length > 0) {
+ $img.attr('alt', '');
+ }
+
+ var $hiddenSpans = $a.find('span').filter(function() {
+ return $(this).css('display') === 'none' || $(this).attr('style')?.includes('display: none');
+ });
+
+ if ($hiddenSpans.length > 0) {
+ $hiddenSpans.each(function() {
+ var $span = $(this);
+ if ($span.text().includes('/uploads/')) {
+ $span.text(i18n.openImg);
+ }
+
+ $span.css({
+ 'display': 'inline-block',
+ 'position': 'absolute',
+ 'width': '1px',
+ 'height': '1px',
+ 'padding': '0',
+ 'margin': '-1px',
+ 'overflow': 'hidden',
+ 'clip': 'rect(0, 0, 0, 0)',
+ 'white-space': 'nowrap',
+ 'border': '0'
+ });
+ });
+ }
+ }
+
+ // E. 重新計算標題 (關鍵邏輯:若 hasOriginalTitle 為真,則不進入此區塊)
+ if (!hasOriginalTitle) {
+ if (linkText === "" && $img.length > 0) {
+ var rawAlt = ($img.attr('alt') || '').trim();
+ var forbidden = ['這是一張圖片', '圖片', 'image', 'photo', '圖', ''];
+ var imgAlt = forbidden.some(function(txt) { return rawAlt.toLowerCase() === txt; })
+ ? ($a.attr('aria-label') || i18n.link) : rawAlt;
+
+ var fileInfo = fileExt ? '[' + fileExt.toUpperCase() + '] ' : '';
+ $a.attr('title', (fileInfo + imgAlt + " " + windowTask).trim());
+ $img.attr('alt', imgAlt);
+ }
+ else if (linkText !== "") {
+ if (fileExt !== "" || hasBadSymbol || currentTitle === "" || currentTitle.includes('/uploads/')) {
+ if (fileExt !== "") {
+ $a.attr('title', linkText + " ." + fileExt + " " + windowTask);
+ } else {
+ $a.attr('title', windowTask);
+ }
+ }
+ }
+ }
+
+ // ✅ 符合 HM1240404E:title 不應與連結文字或圖片 alt 重複
+ if (hasOriginalTitle && currentTitle !== "") {
+ var titleWithoutWindow = currentTitle
+ .replace('(在本視窗開啟)', '')
+ .replace('(在新視窗開啟)', '')
+ .replace('Open in this window', '')
+ .replace('Open in new window', '')
+ .replace('另開新視窗前往', '')
+ .replace('另開新視窗', '')
+ .trim();
+
+ // ✅ title 去掉開窗字串後,若與連結文字或圖片原始 alt 相同,則只保留開窗提示
+ // ✅ 新增:若 linkText 包含副檔名且 title 也是同樣檔名,也只保留開窗提示
+ if (
+ (titleWithoutWindow === linkText && linkText !== i18n.link) ||
+ (imgAltOriginal !== '' && titleWithoutWindow === imgAltOriginal) ||
+ (fileExt !== '' && linkText.toLowerCase().endsWith('.' + fileExt) && titleWithoutWindow === linkText)
+ ) {
+ $a.attr('title', windowTask);
+ return; // ✅ 加上 return,避免繼續執行後面的清理邏輯造成二次污染
+ }
+
+ // ✅ 最終清理:若 title 出現空括號 () 則移除並補上正確開窗提示
+ var finalTitle = ($a.attr('title') || '').trim();
+ if (finalTitle.includes('()')) {
+ finalTitle = finalTitle.replace(/\(\)/g, '').trim();
+ $a.attr('title', finalTitle + ' ' + windowTask);
+ }
+ }
+
+ // F. 最終清理:移除冗餘 label,避免螢幕閱讀器唸兩次
+ $a.removeAttr('aria-label');
});
- // if (location.href.search('editmode=on') === -1) {
- // // 1. 處理圖片 alt 重複問題 (保持原邏輯但優化)
- // $('a').has('img').each(function () {
- // const $link = $(this);
- // const linkText = $link.text().trim();
+ // ✅ G. 補強特定連結(須在迴圈外,因為 javascript: 連結被迴圈跳過)
+ $('.btn-o a').each(function() {
+ var $a = $(this);
+ if (!$a.attr('target')) {
+ $a.attr('target', '_blank');
+ $a.attr('rel', 'noopener noreferrer');
+ }
+ $a.attr('title', isEn ? 'Share to X Open in new window' : '分享至 X 在新視窗開啟');
+ });
- // $link.find('img').each(function () {
- // const $img = $(this);
- // const altText = $img.attr('alt')?.trim();
+ $('.print-button a').each(function() {
+ var $a = $(this);
+ if (!$a.attr('title') || $a.attr('title').trim().toLowerCase() === 'print') {
+ $a.attr('title', isEn ? 'Print this page' : '列印此頁');
+ }
+ });
- // if (altText && altText === linkText) {
- // $img.attr('alt', '');
- // }
- // });
- // });
- // }
+ $('a.i-archive__file-name').each(function () {
+ var $a = $(this);
+ var isNewWindow = ($a.attr('target') === '_blank');
+ $a.attr('title', isNewWindow ? i18n.newWin : i18n.selfWin);
+ });
+ }
+
+ // ✅ 延遲 800ms 確保所有其他 function 執行完畢後才處理
+ setTimeout(function() {
+ fixAccessibilityAll();
+ }, 800);
+});
+
+
$(function() {
function smartFixIcons() {
var isEn = $('html').attr('lang') === 'en';
@@ -1291,9 +1335,9 @@ $(function() {
// 已有 show,不處理
} else {
$('.nav-level-1').removeClass('show');
- $('.nav-level-0>li>.menu-drop').removeClass('opened'); // ✅ 先清除其他的 opened
+ $('.nav-level-0>li>.menu-drop').removeClass('opened'); // 先清除其他的 opened
$(this).parent().find('.nav-level-1').addClass('show');
- $(this).parent().find('.menu-drop').addClass('opened'); // ✅ 加上 opened
+ $(this).parent().find('.menu-drop').addClass('opened'); // 加上 opened
}
});
@@ -1302,7 +1346,7 @@ $(function() {
setTimeout(function() {
if ($li.find(':focus').length === 0) {
$li.find('.nav-level-1').removeClass('show');
- $li.find('.menu-drop').removeClass('opened'); // ✅ 移除 opened
+ $li.find('.menu-drop').removeClass('opened'); // 移除 opened
}
}, 50);
});
@@ -1313,9 +1357,9 @@ $(function() {
// 已有 show,不處理
} else {
$('.nav-level-2').removeClass('show');
- $('.nav-level-1>li>.menu-drop').removeClass('opened'); // ✅ 先清除其他的 opened
+ $('.nav-level-1>li>.menu-drop').removeClass('opened'); // 先清除其他的 opened
$(this).parent().find('.nav-level-2').addClass('show');
- $(this).parent().find('.menu-drop').addClass('opened'); // ✅ 加上 opened
+ $(this).parent().find('.menu-drop').addClass('opened'); // 加上 opened
}
});
@@ -1324,11 +1368,12 @@ $(function() {
setTimeout(function() {
if ($li.find(':focus').length === 0) {
$li.find('.nav-level-2').removeClass('show');
- $li.find('.menu-drop').removeClass('opened'); // ✅ 移除 opened
+ $li.find('.menu-drop').removeClass('opened'); // 移除 opened
}
}, 50);
});
+
$('.controlplay a[role="radio"]').on('click', function () {
// 取消所有的 aria-checked 並還原文字
$('.controlplay a[role="radio"]').attr('aria-checked', 'false');
@@ -1465,92 +1510,7 @@ $(function() {
resizeTimer = setTimeout(fixAccessKeyM, 150);
});
});
- //公告頁籤無障礙
- $(function() {
- function fixTabLinearOrder() {
- // ✅ 只處理內部含有 .tab_nav 的 .w-annc
- var $targetAnnc = $('.w-annc').filter(function() {
- return $(this).find('.tab_nav').length > 0;
- });
- // 若頁面上沒有符合條件的 .w-annc,直接離開
- if ($targetAnnc.length === 0) return;
-
- var $tabs = $targetAnnc.find('.filter_tab');
- var $anncList = $targetAnnc.find('.w-annc__list');
-
- // --- 1. 順向遊走:標籤 -> 對應內容 ---
- $tabs.on('keydown', function(e) {
- if (e.which === 9 && !e.shiftKey) {
- var category = $(this).data('category');
- var $scope = $(this).closest('.w-annc'); // ✅ 限定在同一個 .w-annc
- var $visibleItems = $scope.find('.w-annc__item[data-category="' + category + '"]:visible');
-
- if ($visibleItems.length > 0) {
- var $firstLink = $visibleItems.find('a').first();
- if ($firstLink.length > 0) {
- e.preventDefault();
- $firstLink.focus();
- }
- }
- }
- if (e.which === 13 || e.which === 32) {
- e.preventDefault();
- $(this).click();
- }
- });
-
- // --- 2. 反向遊走:內容 -> 對應標籤 ---
- $anncList.on('keydown', '.w-annc__item a', function(e) {
- var $currentLink = $(this);
- var $currentItem = $currentLink.closest('.w-annc__item');
- var $scope = $currentLink.closest('.w-annc'); // ✅ 限定在同一個 .w-annc
- var category = $currentItem.data('category');
- var $visibleItems = $scope.find('.w-annc__item[data-category="' + category + '"]:visible');
-
- if (e.which === 9 && e.shiftKey) {
- if ($currentLink.is($visibleItems.find('a').first())) {
- e.preventDefault();
- $scope.find('.filter_tab[data-category="' + category + '"]').focus();
- }
- }
-
- if (e.which === 9 && !e.shiftKey) {
- if ($currentLink.is($visibleItems.find('a').last())) {
- var $currentTab = $scope.find('.filter_tab[data-category="' + category + '"]');
- var $nextTab = $currentTab.next('.filter_tab');
- if ($nextTab.length > 0) {
- e.preventDefault();
- $nextTab.focus();
- $nextTab.click();
- }
- }
- }
- });
-
- // --- 3. 反向遊走:標籤 -> 上一個標籤的內容最後一個連結 ---
- $tabs.on('keydown', function(e) {
- if (e.which === 9 && e.shiftKey) {
- var $scope = $(this).closest('.w-annc'); // ✅ 限定在同一個 .w-annc
- var $prevTab = $(this).prev('.filter_tab');
- if ($prevTab.length > 0) {
- var prevCategory = $prevTab.data('category');
- $prevTab.click();
-
- var $prevItems = $scope.find('.w-annc__item[data-category="' + prevCategory + '"]:visible');
- var $lastLink = $prevItems.find('a').last();
-
- if ($lastLink.length > 0) {
- e.preventDefault();
- $lastLink.focus();
- }
- }
- }
- });
- }
-
- fixTabLinearOrder();
- });
//導覽選單子選單無障礙狀態修正 (支援多層級)
function fixNavMenuA11y() {
const $navItems = $('#main-nav li');
@@ -1616,64 +1576,253 @@ $(function() {
// 延遲執行,確保動態產生的選單也能被補強
setTimeout(fixEmptyHref, 500);
});
- //頁籤無障礙
+ //公告頁籤無障礙
$(function() {
- /**
- * 頁籤導覽 (Tab Navigation) 無障礙補強
- * 1. 容器加入 role="tablist"
- * 2. 項目加入 role="tab"
- * 3. 動態切換 aria-selected="true/false"
- * 4. 確保 Enter 鍵可以觸發切換 (針對 tabindex="0" 的優化)
- */
- function fixTabAccessibility() {
- var $tabNav = $('.tab_nav');
- var $tabs = $tabNav.find('.filter_tab');
-
- // --- 1. 初始化結構語意 ---
- $tabNav.attr('role', 'tablist');
-
- $tabs.each(function() {
- var $this = $(this);
- var isActive = $this.hasClass('active');
-
- // 加入頁籤角色與選取狀態
- $this.attr({
- 'role': 'tab',
- 'aria-selected': isActive ? 'true' : 'false'
- });
-
- // 修正 Title:讓使用者知道這是切換頁籤
- var tabName = $this.text().trim();
- $this.attr('title', '切換至 ' + tabName);
+ function fixTabLinearOrder() {
+ var $targetAnnc = $('.w-annc').filter(function() {
+ return $(this).find('.tab_nav').length > 0;
});
- // --- 2. 監聽切換事件 (點擊或鍵盤) ---
- // 假設原本已有切換邏輯,我們在此「補強」屬性的變更
- $tabs.on('click', function() {
- var $clickedTab = $(this);
+ if ($targetAnnc.length === 0) return;
- // 先將所有頁籤設為未選取
- $tabs.attr('aria-selected', 'false');
+ var $tabs = $targetAnnc.find('.filter_tab');
+ var $anncList = $targetAnnc.find('.w-annc__list');
- // 將當前點擊的頁籤設為已選取
- $clickedTab.attr('aria-selected', 'true');
- });
+ // 智慧判斷:偵測 filter_tab 用哪個屬性來分類
+ // 優先用 data-tags(若有值),否則用 data-category
+ function getTabKey($tab) {
+ var tags = $tab.data('tags');
+ if (tags && tags !== '') return { attr: 'data-tags', value: tags };
+ var category = $tab.data('category');
+ if (category && category !== '') return { attr: 'data-category', value: category };
+ return null;
+ }
+
+ // 根據 key 找對應的可見 w-annc__item
+ function getVisibleItems($scope, key) {
+ if (!key) return $();
+ return $scope.find('.w-annc__item[' + key.attr + '="' + key.value + '"]:visible');
+ }
+
+ // 根據 w-annc__item 反查對應的 filter_tab
+ function getTabFromItem($item, $scope) {
+ var tags = $item.data('tags');
+ if (tags && tags !== '') {
+ var $tab = $scope.find('.filter_tab[data-tags="' + tags + '"]');
+ if ($tab.length) return $tab;
+ }
+ var category = $item.data('category');
+ if (category && category !== '') {
+ var $tab = $scope.find('.filter_tab[data-category="' + category + '"]');
+ if ($tab.length) return $tab;
+ }
+ return $();
+ }
- // --- 3. 鍵盤操作補強 (針對 tabindex="0" 的非按鈕元素) ---
$tabs.on('keydown', function(e) {
- // 當按下 Enter (13) 或 Space (32) 時觸發點擊
+ var $scope = $(this).closest('.w-annc');
+ var key = getTabKey($(this));
+
+ // 順向 Tab:頁籤 -> 對應內容第一個連結
+ if (e.which === 9 && !e.shiftKey) {
+ var $visibleItems = getVisibleItems($scope, key);
+ if ($visibleItems.length > 0) {
+ var $firstLink = $visibleItems.find('a').first();
+ if ($firstLink.length > 0) {
+ e.preventDefault();
+ $firstLink.focus();
+ }
+ }
+ }
+
+ // 反向 Shift+Tab:頁籤 -> 上一個頁籤的內容最後一個連結
+ if (e.which === 9 && e.shiftKey) {
+ var $prevTab = $(this).prev('.filter_tab');
+ if ($prevTab.length > 0) {
+ var prevKey = getTabKey($prevTab);
+ $prevTab.click();
+
+ var $prevItems = getVisibleItems($scope, prevKey);
+ var $lastLink = $prevItems.find('a').last();
+
+ if ($lastLink.length > 0) {
+ e.preventDefault();
+ $lastLink.focus();
+ }
+ }
+ }
+
+ // Enter / Space:切換頁籤並移焦點到內容第一個連結
if (e.which === 13 || e.which === 32) {
e.preventDefault();
- $(this).trigger('click');
+ $(this).click();
+
+ var $visibleItems = getVisibleItems($scope, key);
+ var $firstLink = $visibleItems.find('a').first();
+ if ($firstLink.length > 0) {
+ setTimeout(function() { $firstLink.focus(); }, 50);
+ }
+ }
+ });
+
+ // 反向遊走:內容 -> 對應標籤;Tab 到最後一個連結跳下一個頁籤
+ $anncList.on('keydown', '.w-annc__item a', function(e) {
+ var $currentLink = $(this);
+ var $currentItem = $currentLink.closest('.w-annc__item');
+ var $scope = $currentLink.closest('.w-annc');
+
+ // 找出當前 item 對應的 filter_tab
+ var $currentTab = getTabFromItem($currentItem, $scope);
+ if (!$currentTab.length) return;
+
+ // 找出同類別的所有可見 item
+ var key = getTabKey($currentTab);
+ var $visibleItems = getVisibleItems($scope, key);
+
+ // Shift+Tab:若是第一個連結,跳回對應頁籤
+ if (e.which === 9 && e.shiftKey) {
+ if ($currentLink.is($visibleItems.find('a').first())) {
+ e.preventDefault();
+ $currentTab.focus();
+ }
+ }
+
+ // Tab:若是最後一個連結,跳到下一個頁籤並切換
+ if (e.which === 9 && !e.shiftKey) {
+ if ($currentLink.is($visibleItems.find('a').last())) {
+ var $nextTab = $currentTab.next('.filter_tab');
+ if ($nextTab.length > 0) {
+ e.preventDefault();
+ $nextTab.focus();
+ $nextTab.click();
+ }
+ }
}
});
}
- // 延遲執行確保頁籤元件已渲染
+ setTimeout(fixTabLinearOrder, 500);
+ });
+ //頁籤無障礙
+ $(function () {
+ function fixTabAccessibility() {
+
+ // 各自獨立處理每組 .tab_nav,避免多組時跨區塊操作問題
+ $('.tab_nav').each(function() {
+ var $tabNav = $(this);
+ var $tabs = $tabNav.find('li');
+
+ // --- 1. 初始化結構語意 ---
+ $tabNav.attr('role', 'tablist');
+
+ $tabs.each(function () {
+ var $this = $(this);
+ var isActive = $this.hasClass('active');
+
+ $this.attr({
+ 'role': 'tab',
+ 'aria-selected': isActive ? 'true' : 'false',
+ 'tabindex': isActive ? '0' : '-1'
+ });
+
+ var tabName = $this.text().trim();
+ $this.attr('title', '切換至 ' + tabName);
+ });
+
+ // --- 2. 點擊事件:更新 aria-selected 與 tabindex ---
+ $tabs.on('click', function () {
+ var $clickedTab = $(this);
+
+ $tabs.attr('aria-selected', 'false').attr('tabindex', '-1');
+ $clickedTab.attr('aria-selected', 'true').attr('tabindex', '0');
+ });
+
+ // --- 3. 鍵盤操作補強 ---
+ $tabs.on('keydown', function (e) {
+ var $current = $(this);
+ var currentIndex = $tabs.index($current);
+ var lastIndex = $tabs.length - 1;
+ var $target = null;
+
+ switch (e.which) {
+ case 13: // Enter
+ case 32: // Space
+ e.preventDefault();
+ $current.trigger('click');
+ break;
+
+ case 37: // ← 左方向鍵:移到前一個頁籤
+ case 38: // ↑ 上方向鍵
+ e.preventDefault();
+ $target = currentIndex > 0
+ ? $tabs.eq(currentIndex - 1)
+ : $tabs.eq(lastIndex);
+ break;
+
+ case 39: // → 右方向鍵:移到下一個頁籤
+ case 40: // ↓ 下方向鍵
+ e.preventDefault();
+ $target = currentIndex < lastIndex
+ ? $tabs.eq(currentIndex + 1)
+ : $tabs.eq(0);
+ break;
+
+ case 36: // Home:跳到第一個頁籤
+ e.preventDefault();
+ $target = $tabs.eq(0);
+ break;
+
+ case 35: // End:跳到最後一個頁籤
+ e.preventDefault();
+ $target = $tabs.eq(lastIndex);
+ break;
+ }
+
+ // 移動焦點並觸發點擊切換
+ if ($target && $target.length) {
+ $tabs.attr('tabindex', '-1');
+ $target.attr('tabindex', '0').focus().trigger('click');
+ }
+ });
+ });
+ }
+
setTimeout(fixTabAccessibility, 500);
});
+
+
+ //移除 accesskey="W" 之後的 | 符號
+ $(function() {
+ function removeSeparatorAfterAccesskeyW() {
+ $('a[accesskey="W"]').each(function() {
+ // 取得 a 標籤相鄰的下一個 DOM 節點
+ var nextNode = this.nextSibling;
+
+ // 檢查節點是否存在、是否為文字節點 (nodeType 3),且是否包含 '|'
+ if (nextNode && nextNode.nodeType === 3) {
+ var textValue = nextNode.nodeValue;
+ if (textValue.includes('|')) {
+ // 將 '|' 替換為空字串並更新節點值
+ nextNode.nodeValue = textValue.replace('|', '');
+ }
+ }
+ });
+ }
+
+ // 執行處理
+ removeSeparatorAfterAccesskeyW();
+ });
+ if ($('#language-li').is(':empty') || $('#language-li').html().trim() === '') {
+ $('#language-li').remove();
+ };
+ $('.header-nav').each(function() {
+ const cleaned = $(this).text().replace(/[\s|]/g, '');
+ if (cleaned === '') {
+ $(this).remove();
+ }
+ });
}
- forFreeGo();
+ forFreeGo();