diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js
index db94897..13e12b7 100644
--- a/assets/javascripts/app.js
+++ b/assets/javascripts/app.js
@@ -729,97 +729,37 @@
$this.attr('title', '按鈕');
}
});
- //img無障礙
- $(function() {
- /**
- * 圖片無障礙 AA 級補強 (人工檢測優化版)
- * 1. 處理裝飾性圖片:清空 alt 並移除 title。
- * 2. 解決資訊冗餘:若 alt 與 title 內容相同,移除 title,避免重複朗讀。
- * 3. 自動補強缺失 alt:從父層 title 或鄰近標題文字擷取。
- */
- function fixImageAccessibility() {
- $('img').each(function() {
- var $img = $(this);
- var currentAlt = ($img.attr('alt') || '').trim();
- var currentTitle = ($img.attr('title') || '').trim();
- // --- 1. 處理「裝飾性圖片」標註 (最高優先權) ---
- if (currentAlt === "裝飾圖片" || currentTitle === "裝飾圖片") {
- $img.attr('alt', '');
- $img.removeAttr('title');
- return; // 跳過此圖
- }
+ function removeEmptyTitles() {
+ // 定義所有需要檢查的 class
+ const targetClasses = [
+ '.w-annc__widget-title',
+ '.widget-title',
+ '.show-title',
+ '.event-annc-title',
+ '.annc-title',
+ '.sitemenu-title',
+ '.widget-link__widget-title'
+ ];
- // --- 2. 解決【alt 與 title 相同】的問題 (人工檢測重點) ---
- // 只要兩者內容一致且不為空,就移除 title,保留 alt
- if (currentAlt !== '' && currentAlt === currentTitle) {
- $img.removeAttr('title');
- // 重新更新變數值供後續邏輯使用
- currentTitle = '';
- }
+ // 將陣列轉換為 jQuery 選擇器字串
+ const selector = targetClasses.join(', ');
- // --- 3. 處理「缺失 alt」或「空的 alt」補強邏輯 ---
- if (currentAlt === '') {
- let finalAlt = "";
+ $(selector).each(function() {
+ // 使用 $.trim 移除空格、換行符號
+ // 然後檢查裡面是否完全沒有文字
+ const textContent = $.trim($(this).text());
- // A. 嘗試從父層 (如 ) 的 title 抓取描述
- var parentTitle = $img.parent().attr('title');
-
- // B. 嘗試抓取同區域內的標題文字
- var nearbyTitle = $img.closest('a').find('h1, h2, h3, h4, h5, h6').first().text().trim();
-
- if (parentTitle && parentTitle.trim() !== '') {
- finalAlt = parentTitle.trim();
- } else if (nearbyTitle !== '') {
- finalAlt = nearbyTitle;
- }
-
- // 寫入最終 alt 結果
- // 如果 finalAlt 仍為空,則設為 "" (符合 AA 規範,視為裝飾圖)
- $img.attr('alt', finalAlt);
-
- // --- 4. 二次清理:補強後的 alt 如果又跟原本的 title 一樣,則移除 title ---
- if (currentTitle !== '' && currentTitle === finalAlt) {
- $img.removeAttr('title');
- }
- }
- });
- }
-
- // 延遲執行確保圖片與動態內容已渲染
- setTimeout(fixImageAccessibility, 500);
+ if (textContent === "") {
+ // 如果沒有文字,則將整個元素刪除
+ $(this).remove();
+ }
+ });
+ }
+ // 執行 function
+ $(document).ready(function() {
+ removeEmptyTitles();
});
- function removeEmptyTitles() {
- // 定義所有需要檢查的 class
- const targetClasses = [
- '.w-annc__widget-title',
- '.widget-title',
- '.show-title',
- '.event-annc-title',
- '.annc-title',
- '.sitemenu-title',
- '.widget-link__widget-title'
- ];
-
- // 將陣列轉換為 jQuery 選擇器字串
- const selector = targetClasses.join(', ');
-
- $(selector).each(function() {
- // 使用 $.trim 移除空格、換行符號
- // 然後檢查裡面是否完全沒有文字
- const textContent = $.trim($(this).text());
-
- if (textContent === "") {
- // 如果沒有文字,則將整個元素刪除
- $(this).remove();
- }
- });
- }
-
- // 執行 function
- $(document).ready(function() {
- removeEmptyTitles();
- });
$(".w-annc__img-wrap a").each(function () {
var $this = $(this);
// 確保 內沒有文字節點 (避免重複添加)
@@ -879,99 +819,181 @@
$button.attr('aria-label', '播放驗證碼語音');
}
});
- //有連結目的之所有a標籤的無障礙處理
- $(function() {
-
- /**
- * 全站無障礙 AA 級補強 (多語系偵測版)
- * 支援功能:語系自動偵測、HM1240404E 修正、檔案預知類型、圖片替代文字
- */
- function fixAccessibilityAll() {
- // 1. 偵測目前頁面語系 (優先抓取 html lang,若無則預設為 zh-Hant)
- var pageLang = $('html').attr('lang') || 'zh-Hant';
- var isEn = pageLang.toLowerCase().startsWith('en');
-
- // 2. 定義語系對應字典
- 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' : '連結'
- };
-
- // --- 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();
-
- // 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. 智慧修正與標題補充 (解決 HM1240404E 不明符號問題)
- // 檢查是否包含括號 () 或 中英文的另開視窗關鍵字
- 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;
+ // img無障礙
+ $(function() {
+ /**
+ * 圖片無障礙 AA 級補強 (人工檢測優化版)
+ */
+ 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();
- var fileInfo = fileExt ? '[' + fileExt.toUpperCase() + '] ' : '';
- $a.attr('title', (fileInfo + 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;
+ // 判定該連結是否「僅靠圖片傳達目的」(連結內無文字)
+ var isLinkImage = $parentA.length > 0 && $parentA.text().replace(/\u00a0/g, '').trim() === "";
+
+ // --- 1. 處理「裝飾性圖片」標註 ---
+ if (currentAlt === "裝飾圖片" || currentTitle === "裝飾圖片") {
+ $img.attr('alt', '');
+ $img.removeAttr('title');
+ return;
+ }
+
+ // --- 2. 解決【alt 與 title 相同】的問題 ---
+ if (currentAlt !== '' && currentAlt === currentTitle) {
+ $img.removeAttr('title');
+ currentTitle = '';
+ }
+
+ // --- 3. 處理「缺失 alt」或「空的 alt」補強邏輯 ---
+ // 修改點:若是具有連結用途的圖片,alt 不可為空
+ if (currentAlt === '') {
+ let finalAlt = "";
+
+ // A. 優先嘗試從父層 () 的 title 抓取
+ var parentATitle = $parentA.attr('title');
- if (fileExt !== "") {
- // 檔案下載:連結文字 + .副檔名 + 動作 (語系化)
- $a.attr('title', linkText + " ." + fileExt + " " + windowTask);
- } else if (linkText.length <= 6 || isTag) {
- // 短文字:補充完整語意
- $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');
}
}
+ });
+ }
+
+ 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');
+
+ 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' : '連結'
+ };
+
+ // --- Part 1: 語言選單修正 ---
+ var $langBtn = $('#languagebutton');
+ if ($langBtn.length > 0) {
+ $langBtn.attr('title', i18n.langBtn);
+ $langBtn.removeAttr('aria-label');
}
- // D. 最終清理
- $a.removeAttr('aria-label');
- if (linkText !== "" && $img.length > 0) { $img.attr('alt', ''); }
- });
- }
+ // --- Part 2: 全站連結處理 ---
+ $('a').each(function() {
+ var $a = $(this);
+ var href = ($a.attr('href') || '').toLowerCase();
+ if (!href || href.startsWith('javascript:')) return;
- setTimeout(function() {
- fixAccessibilityAll();
- }, 600);
- });
+ // 清理 與 空白
+ 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);
+ }
+ }
+ });
+ }
+
+ setTimeout(function() {
+ fixAccessibilityAll();
+ }, 600);
+ });
// if (location.href.search('editmode=on') === -1) {
// // 1. 處理圖片 alt 重複問題 (保持原邏輯但優化)
@@ -1189,15 +1211,20 @@
setTimeout(fixJPlayerAccessibility, 500);
});
+ // 移除 .navbar-brand 內部 display:none 元素的補強
function removeHiddenElementsInsideBrand() {
// 選取 .navbar-brand 內部所有隱藏的元素
$('.navbar-brand *').filter(function() {
+ // 同時判定 inline style 與 CSS class 造成的 display: none
return $(this).css('display') === 'none';
- }).remove(); // 徹底從 DOM 中移除該標籤
+ }).remove(); // 徹底從 DOM 中移除該標籤,避免無障礙檢測工具誤判
}
- // 執行 function
- removeHiddenElementsInsideBrand();
+ // 使用 setTimeout 確保內容渲染後執行
+ // 建議設定 500~800 毫秒,避開大部分動態載入的時間差
+ setTimeout(function() {
+ removeHiddenElementsInsideBrand();
+ }, 600);
//修正 Alt+M 定位點位置
$(function() {
function fixAccessKeyM() {