From 4ad05fd88ac8bab240189b313228173993d3b8c7 Mon Sep 17 00:00:00 2001 From: ken Date: Tue, 7 Apr 2026 20:01:56 +0800 Subject: [PATCH] 'js' --- assets/javascripts/app.js | 1247 ++++++++++------- .../template/base/_go_back_top.scss | 18 +- .../stylesheets/template/layout/content.scss | 3 +- .../stylesheets/template/layout/header.scss | 12 +- .../template/modules/announcement.scss | 10 +- .../stylesheets/template/modules/hashtag.scss | 4 +- .../stylesheets/template/modules/member.scss | 6 +- .../template/modules/web_resource.scss | 1 - assets/stylesheets/template/template.scss | 5 +- modules/member/member_index2.html.erb | 8 +- modules/video_pro/video_pro_index2.html.erb | 2 +- .../video_pro/video_pro_index2_tag.html.erb | 2 +- modules/video_pro/video_pro_index4.html.erb | 2 +- .../web_resource/_web_res_widget5.html.erb | 2 +- .../web_resource/_web_res_widget6.html.erb | 2 +- 15 files changed, 815 insertions(+), 509 deletions(-) diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js index 18e424e..5dfbb49 100644 --- a/assets/javascripts/app.js +++ b/assets/javascripts/app.js @@ -398,25 +398,8 @@ // }else{ // $('.header-buttom').appendTo($('.dropdowns')); // } - function forFreeGo() { - - setTimeout(function() { - // 針對該特定類別進行檢查 - $('.w-annc__widget-title').each(function() { - var $title = $(this); - - // 取得內部的純文字內容(移除前後空白) - var textContent = $.trim($title.text()); - - // 檢查是否含有具體的「內容」元素,例如圖片、iframe 或 icon - // 排除掉掉你範例中那種用來排版的空 div 或空 span - var hasRealContent = $title.find('img, i, svg, canvas').length > 0; - - // 判斷條件:如果沒有文字且沒有具體內容元素 - if (textContent === "" && !hasRealContent) { - $title.remove(); - } - }); + function forFreeGo() { + setTimeout(function() { $('h1, h2, h3, h4, h5, h6').each(function() { var $heading = $(this); @@ -425,8 +408,8 @@ $heading.remove(); } }); - }, 500); - //zoom + }, 500); + //zoom $(function () { $('.fnav a').each(function () { const $a = $(this); @@ -499,479 +482,688 @@ $el.remove(); } }); - //表單legend - $("fieldset").each(function () { - const $fieldset = $(this); - const hasLegend = $fieldset.children("legend").length > 0; + //表單legend + $("fieldset").each(function () { + const $fieldset = $(this); + const hasLegend = $fieldset.children("legend").length > 0; - if (!hasLegend) { - // 嘗試抓最上層的群組標題,例如 "Apply" - const headingText = $fieldset.find(".form-group:first").text().trim() || "表單填寫"; + if (!hasLegend) { + // 嘗試抓最上層的群組標題,例如 "Apply" + const headingText = $fieldset.find(".form-group:first").text().trim() || "表單填寫"; - // 插入 legend 為第一個元素 - $fieldset.prepend(`${headingText}`); - } - }); - - // 處理「上一頁」按鈕 - $(".cmdBackward").each(function () { - $(this) - .attr("title", "上一頁") - .attr("aria-label", "上一頁"); - - if ($(this).find(".sr-only").length === 0) { - $(this).append('上一頁'); - } - - $(this).find("i").attr("aria-hidden", "true"); - $(this).find(".icon").attr("aria-hidden", "true"); - }); - - // 處理「下一頁」按鈕 - $(".cmdForward").each(function () { - $(this) - .attr("title", "下一頁") - .attr("aria-label", "下一頁"); - - if ($(this).find(".sr-only").length === 0) { - $(this).append('下一頁'); - } - - $(this).find("i").attr("aria-hidden", "true"); - $(this).find(".icon").attr("aria-hidden", "true"); - }); - - $('.pagination li.active a').attr('aria-current', 'page'); + // 插入 legend 為第一個元素 + $fieldset.prepend(`${headingText}`); + } + }); - $('path').each(function () { + // 處理「上一頁」按鈕 + $(".cmdBackward").each(function () { $(this) - .attr('aria-hidden', 'true') - .attr('focusable', 'false') - .attr('tabindex', '-1'); + .attr("title", "上一頁") + .attr("aria-label", "上一頁"); + + if ($(this).find(".sr-only").length === 0) { + $(this).append('上一頁'); + } + + $(this).find("i").attr("aria-hidden", "true"); + $(this).find(".icon").attr("aria-hidden", "true"); }); - $('.controlplay a[role="radio"]').on('click', function () { - // 取消所有的 aria-checked 並還原文字 - $('.controlplay a[role="radio"]').attr('aria-checked', 'false'); - $('.controlplay a[role="radio"] span').each(function () { - var text = $(this).text().replace('(已選取)', ''); - $(this).text(text); + // 處理「下一頁」按鈕 + $(".cmdForward").each(function () { + $(this) + .attr("title", "下一頁") + .attr("aria-label", "下一頁"); + + if ($(this).find(".sr-only").length === 0) { + $(this).append('下一頁'); + } + + $(this).find("i").attr("aria-hidden", "true"); + $(this).find(".icon").attr("aria-hidden", "true"); }); - - // 設定目前被點擊的按鈕為已選取 - $(this).attr('aria-checked', 'true'); - var selectedText = $(this).text().trim(); - $(this).find('span').text(selectedText + '(已選取)'); - }); - // 遍历所有的 .s-annc__tag-wrap 元素 - $('.s-annc__tag-wrap').each(function() { - // 遍历 .s-annc__tag-wrap 下的每个 a 元素 - $(this).find('a').each(function() { - // 如果 .s-annc__tag 元素为空或没有内容 - if ($(this).find('.s-annc__tag').is(':empty')) { - // 移除该 a 元素 - $(this).remove(); - } + + $('.pagination li.active a').attr('aria-current', 'page'); + + $('path').each(function () { + $(this) + .attr('aria-hidden', 'true') + .attr('focusable', 'false') + .attr('tabindex', '-1'); }); - }); - $('.w-ba-banner__caption li button').each(function (index) { - const $slide = $('.w-ba-banner__slide').eq(index); - const title = $slide.attr('data-cycle-title')?.trim(); + $('.controlplay a[role="radio"]').on('click', function () { + // 取消所有的 aria-checked 並還原文字 + $('.controlplay a[role="radio"]').attr('aria-checked', 'false'); + $('.controlplay a[role="radio"] span').each(function () { + var text = $(this).text().replace('(已選取)', ''); + $(this).text(text); + }); - if (title) { - const fullText = title + '的pager'; - $(this).attr('aria-label', fullText); - $(this).attr('title', fullText); - } + // 設定目前被點擊的按鈕為已選取 + $(this).attr('aria-checked', 'true'); + var selectedText = $(this).text().trim(); + $(this).find('span').text(selectedText + '(已選取)'); }); - // 當 focus 到 menu link 時,顯示對應 ul - $('.sitemenu-item > a').on('focus', function () { - $(this).siblings('ul').addClass('show'); - }); - - // 當 focus 離開最後一個子選單 link 時,移除 .show - $('.sitemenu-item').each(function () { - const $submenuLinks = $(this).find('ul a'); - - if ($submenuLinks.length > 0) { - $submenuLinks.last().on('blur', function () { - // 當最後一個子項 blur 時關閉 ul - $(this).closest('ul').removeClass('show'); - }); - } else { - // 若沒有子項,當主選單項 blur 也隱藏 - $(this).find('> a').on('blur', function () { - $(this).siblings('ul').removeClass('show'); - }); - } - }); - if (document.documentElement.lang === 'zh_tw') { - document.documentElement.lang = 'zh-Hant'; - } - //tab鍵按下 - $(document).on('keydown', function(e) { - if (e.key === "Tab" || e.keyCode === 9) { - $('.header-nav, .dropdowns').css('display', 'block'); - } - }); - - //li被hover - function handleHover() { - if ($(window).width() > 769) { - $('li').off('mouseenter mouseleave').hover( - function() { - $(this).children('ul').addClass('show'); - }, - function() { - $(this).children('ul').removeClass('show'); - } - ); - } else { - $('li').off('mouseenter mouseleave'); // 移除 hover 事件 - } - } - - // 先執行一次 - handleHover(); - - // 監聽視窗大小變化 - $(window).on('resize', function() { - handleHover(); - }); - //刪除空的h1 - $('h1').each(function() { - if ($(this).text().trim() === '') { - $(this).remove(); - } - }); - //refresh_btn加上aria-label - $('#refresh_btn').each(function() { - var $this = $(this); - - // 如果 button 尚未有 aria-label,則新增 - if (!$this.attr('aria-label')) { - $this.attr('aria-label', '重新整理'); - } - }); - //無障礙會員表格刪除沒有顯示的th - $('.i-member-tr-head').each(function() { - if ($(this).css('display') === 'none') { - $(this).remove(); - } - }); - //無障礙公告a是空的 - $('.w-annc__subtitle').each(function () { - var $this = $(this); - var $link = $this.find('a'); - - // 檢查 a 是否存在,且去除空白後是否為空字串 - if ($link.length && $link.text().trim() === '') { - $this.remove(); // 移除外層 .w-annc__subtitle - } - }); - //無障礙單位轉換 - $("[style*='font-size']").each(function() { - var fontSize = $(this).css("font-size"); - if (fontSize.includes("px")) { - var pxValue = parseFloat(fontSize); // 取得數值 - var emValue = pxValue / 16; // 假設 1em = 16px - $(this).css("font-size", emValue + "em"); - } - }); - $("[style*='font-size']").each(function() { - var fontSize = $(this).css("font-size"); - if (fontSize.includes("pt")) { - var ptValue = parseFloat(fontSize); // 取得數值 - var emValue = ptValue / 12; // 1em = 12pt(一般轉換標準) - $(this).css("font-size", emValue + "em"); - } - }); - $("[style*='font-size']").each(function() { - var styleAttr = $(this).attr("style"); // 取得原始 style 屬性字串 - var match = styleAttr.match(/font-size\s*:\s*(\d+(?:\.\d+)?)pt/i); - if (match) { - var ptValue = parseFloat(match[1]); - var emValue = ptValue / 12; - // 替換 style 屬性字串中的 pt 為 em - var newStyle = styleAttr.replace(/font-size\s*:\s*\d+(?:\.\d+)?pt/i, `font-size: ${emValue}em`); - $(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"); - } - }); - }); - }); - $(".banner-pager button").addClass('banner-pagerbtn'); - $(".banner-pager button").attr("type","button"); - $(".banner-pager button").append('下一張'); - $("button").attr("role", "button"); - $("select").attr("title","選擇類別"); - $(".jarallax-video-audio").attr("role", "button"); - $('button').each(function() { - var $this = $(this); - if (!$this.attr('title') || $this.attr('title').trim() === '') { - $this.attr('title', '按鈕'); - } - }); - $('img').each(function() { - var $this = $(this); - if (!$this.attr('alt') || $this.attr('alt').trim() === '') { - $this.attr('alt', '這是一張圖片'); - } - }); - $('img').each(function() { - var $this = $(this); - if (!$this.attr('title') || $this.attr('title').trim() === '') { - $this.attr('title', '這是一張圖片'); - } - }); - $('img').each(function() { - var $this = $(this); - - // 檢查 img 的 alt 屬性是否為 "裝飾圖片" - if ($this.attr('alt') === "裝飾圖片" || $this.attr('title') === "裝飾圖片") { - // 設定 alt 為空字串 - $this.attr('alt', ''); - - // 移除 title 屬性 - $this.removeAttr('title'); + // 遍历所有的 .s-annc__tag-wrap 元素 + $('.s-annc__tag-wrap').each(function() { + // 遍历 .s-annc__tag-wrap 下的每个 a 元素 + $(this).find('a').each(function() { + // 如果 .s-annc__tag 元素为空或没有内容 + if ($(this).find('.s-annc__tag').is(':empty')) { + // 移除该 a 元素 + $(this).remove(); } }); - $(".w-annc__img-wrap a").each(function () { - var $this = $(this); - // 確保 內沒有文字節點 (避免重複添加) - if ($this.text().trim() === "") { - $this.append('公告圖片'); + }); + + $('.w-ba-banner__caption li button').each(function (index) { + const $slide = $('.w-ba-banner__slide').eq(index); + const title = $slide.attr('data-cycle-title')?.trim(); + + if (title) { + const fullText = title + '的pager'; + $(this).attr('aria-label', fullText); + $(this).attr('title', fullText); } + }); + // 當 focus 到 menu link 時,顯示對應 ul + $('.sitemenu-item > a').on('focus', function () { + $(this).siblings('ul').addClass('show'); }); - $(".widget-link__widget-title").each(function () { + + // 當 focus 離開最後一個子選單 link 時,移除 .show + $('.sitemenu-item').each(function () { + const $submenuLinks = $(this).find('ul a'); + + if ($submenuLinks.length > 0) { + $submenuLinks.last().on('blur', function () { + // 當最後一個子項 blur 時關閉 ul + $(this).closest('ul').removeClass('show'); + }); + } else { + // 若沒有子項,當主選單項 blur 也隱藏 + $(this).find('> a').on('blur', function () { + $(this).siblings('ul').removeClass('show'); + }); + } + }); + if (document.documentElement.lang === 'zh_tw') { + document.documentElement.lang = 'zh-Hant'; + } + //tab鍵按下 + $(document).on('keydown', function(e) { + if (e.key === "Tab" || e.keyCode === 9) { + $('.header-nav, .dropdowns').css('display', 'block'); + } + }); + + function handleHover() { + // 先統一移除舊事件,避免重複綁定 + $('li').off('mouseenter mouseleave focusin focusout'); + + if ($(window).width() > 769) { + // 1. 處理滑鼠 Hover + $('li').hover( + function() { $(this).children('ul').addClass('show'); }, + function() { $(this).children('ul').removeClass('show'); } + ); + + // 2. 處理鍵盤 Tab 聚焦 (關鍵修正) + $('li').on('focusin', function() { + // 當焦點進入 li 或其子元素時,顯示選單 + $(this).children('ul').addClass('show'); + }); + + $('li').on('focusout', function() { + var $this = $(this); + // 延遲偵測焦點是否真的「離開」了這個 li 區塊 + setTimeout(function() { + // 如果新的焦點不在當前這個 li 裡面,才移除 show + if ($this.find(':focus').length === 0) { + $this.children('ul').removeClass('show'); + } + }, 10); + }); + } + } + + // 初始化與 Resize 監聽保持不變 + handleHover(); + $(window).on('resize', function() { + handleHover(); + }); + //刪除空的h1 + $('h1').each(function() { + if ($(this).text().trim() === '') { + $(this).remove(); + } + }); + //refresh_btn加上aria-label + $('#refresh_btn').each(function() { + var $this = $(this); + + // 如果 button 尚未有 aria-label,則新增 + if (!$this.attr('aria-label')) { + $this.attr('aria-label', '重新整理'); + } + }); + //無障礙會員表格刪除沒有顯示的th + $('.i-member-tr-head').each(function() { + if ($(this).css('display') === 'none') { + $(this).remove(); + } + }); + //無障礙公告a是空的 + $('.w-annc__subtitle').each(function () { + var $this = $(this); + var $link = $this.find('a'); + + // 檢查 a 是否存在,且去除空白後是否為空字串 + if ($link.length && $link.text().trim() === '') { + $this.remove(); // 移除外層 .w-annc__subtitle + } + }); + //無障礙單位轉換 + $(function() { + $('style:contains("font-size")').each(function() { + let css = $(this).html(); + css = css.replace(/font-size\s*:\s*([\d.]+)px\s*;?/gi, (_, px) => + `font-size: ${(parseFloat(px) / 16).toFixed(3)}em;` + ); + $(this).html(css); + }); + }); + + $("[style*='font-size']").each(function() { + var fontSize = $(this).css("font-size"); + if (fontSize.includes("px")) { + var pxValue = parseFloat(fontSize); // 取得數值 + var emValue = pxValue / 16; // 假設 1em = 16px + $(this).css("font-size", emValue + "em"); + } + }); + $("[style*='font-size']").each(function() { + var fontSize = $(this).css("font-size"); + if (fontSize.includes("pt")) { + var ptValue = parseFloat(fontSize); // 取得數值 + var emValue = ptValue / 12; // 1em = 12pt(一般轉換標準) + $(this).css("font-size", emValue + "em"); + } + }); + $("[style*='font-size']").each(function() { + var styleAttr = $(this).attr("style"); // 取得原始 style 屬性字串 + var match = styleAttr.match(/font-size\s*:\s*(\d+(?:\.\d+)?)pt/i); + if (match) { + var ptValue = parseFloat(match[1]); + var emValue = ptValue / 12; + // 替換 style 屬性字串中的 pt 為 em + var newStyle = styleAttr.replace(/font-size\s*:\s*\d+(?:\.\d+)?pt/i, `font-size: ${emValue}em`); + $(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"); + } + }); + }); + }); + $(".banner-pager button").addClass('banner-pagerbtn'); + $(".banner-pager button").attr("type","button"); + $(".banner-pager button").append('下一張'); + $("button").attr("role", "button"); + $("select").attr("title","選擇類別"); + $(".jarallax-video-audio").attr("role", "button"); + $('button').each(function() { + var $this = $(this); + if (!$this.attr('title') || $this.attr('title').trim() === '') { + $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; // 跳過此圖 + } + + // --- 2. 解決【alt 與 title 相同】的問題 (人工檢測重點) --- + // 只要兩者內容一致且不為空,就移除 title,保留 alt + if (currentAlt !== '' && currentAlt === currentTitle) { + $img.removeAttr('title'); + // 重新更新變數值供後續邏輯使用 + currentTitle = ''; + } + + // --- 3. 處理「缺失 alt」或「空的 alt」補強邏輯 --- + if (currentAlt === '') { + let finalAlt = ""; + + // 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); +}); + $(".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('公告標題'); + } + }); + $(".sitemenu-title").each(function () { if ($(this).text().trim() === "") { - $(this).append('公告標題'); + $(this).append('次選單'); } }); - $(".sitemenu-title").each(function () { - if ($(this).text().trim() === "") { - $(this).append('次選單'); - } - }); - $(".annc-title").each(function () { - if ($(this).text().trim() === "") { - $(this).append('內頁公告標題'); - } - }); - $(".event-annc-title").each(function () { - if ($(this).text().trim() === "") { - $(this).append('內頁活動公告標題'); - } - }); - $(".show-title").each(function () { - if ($(this).text().trim() === "") { - $(this).append('內頁活動公告標題'); - } - }); - $(".w-annc__widget-title").each(function () { - if ($(this).text().trim() === "") { - $(this).append('公告標題'); - } - }); - $(".widget-title").each(function () { - if ($(this).text().trim() === "") { - $(this).append('網路資源標題'); - } - }); - $(".widget-title").each(function () { - if ($(this).text().trim() === "") { - $(this).append('網路資源標題'); - } - }); - $('input').each(function() { - var $this = $(this); - if (!$this.attr('title') || $this.attr('title').trim() === '') { - $this.attr('title', '網內搜尋'); - } - }); - $('.rucaptcha-image').each(function() { - var $button = $(this).next('button'); // 取得緊接在 .rucaptcha-image 之後的 button - if ($button.length && !$button.attr('aria-label')) { - $button.attr('aria-label', '播放驗證碼語音'); - } - }); + $(".annc-title").each(function () { + if ($(this).text().trim() === "") { + $(this).append('內頁公告標題'); + } + }); + $(".event-annc-title").each(function () { + if ($(this).text().trim() === "") { + $(this).append('內頁活動公告標題'); + } + }); + $(".show-title").each(function () { + if ($(this).text().trim() === "") { + $(this).append('內頁活動公告標題'); + } + }); + $(".w-annc__widget-title").each(function () { + if ($(this).text().trim() === "") { + $(this).append('公告標題'); + } + }); + $(".widget-title").each(function () { + if ($(this).text().trim() === "") { + $(this).append('網路資源標題'); + } + }); + $(".widget-title").each(function () { + if ($(this).text().trim() === "") { + $(this).append('網路資源標題'); + } + }); + $('input').each(function() { + var $this = $(this); + if (!$this.attr('title') || $this.attr('title').trim() === '') { + $this.attr('title', '網內搜尋'); + } + }); + $('.rucaptcha-image').each(function() { + var $button = $(this).next('button'); // 取得緊接在 .rucaptcha-image 之後的 button + if ($button.length && !$button.attr('aria-label')) { + $button.attr('aria-label', '播放驗證碼語音'); + } + }); //有連結目的之所有a標籤加上aria-label和title - $('a').each(function () { - var $a = $(this); - var href = $a.attr('href'); - if (!href) return; - - var hasSrOnly = $a.find('.sr-only').length > 0; - - // 若有 .sr-only,移除 aria-label 和 title 避免重複朗讀 - if (hasSrOnly) { - $a.removeAttr('aria-label'); - $a.removeAttr('title'); - return; // 有 .sr-only 就不做其他處理 - } - - // ----- aria-label 邏輯 ----- - if (!$a.attr('aria-label')) { - let ariaLabel = ''; - - // 加入開啟方式 - if ($a.attr('target') === '_blank') { - ariaLabel += '在新視窗開啟 '; - } else if ($a.attr('target') === '_self') { - ariaLabel += '在本視窗開啟 '; +$(function() { + /** + * 無障礙 AA 級補強最終整合版 (人工檢測完全合格) + * 1. 修正語言選單:Tab 到達時顯示「在本視窗開啟語言選單」。 + * 2. 智慧 Title 策略: + * - 長文字:僅保留動作提示 (如: (在本視窗開啟)),避免重複讀取。 + * - 短文字/標籤:組合 [文字內容] + [動作提示],增強目的識別。 + * 3. 圖文並存處理:符合 HM1240402E,當有文字時,圖片 alt 設為空值。 + * 4. 清理無效描述:攔截「這是一張圖片」等不合格內容。 + */ + function fixAccessibilityAll() { + // --- Part 1: 語言選單修正 (Language Button) --- + var $langBtn = $('#languagebutton'); + if ($langBtn.length > 0) { + $langBtn.attr('title', '在本視窗開啟語言選單'); + $langBtn.removeAttr('aria-label'); } - // 如果包含圖片且有圖片 title - if ($a.find('img').length) { - const imgTitle = $a.find('img').attr('title'); - if (imgTitle) ariaLabel = imgTitle; - } else { - const text = $a.text().trim(); - if (text) { - ariaLabel += text; - } else if ($a.children('span').length === 1) { - ariaLabel += $a.children('span').text().trim(); - } - } + // --- Part 2: 全站連結補強 (Links) --- + $('a').each(function() { + var $a = $(this); + var href = $a.attr('href'); + + // 基礎攔截 + if (!href || href.startsWith('javascript:')) return; - if (ariaLabel) { - $a.attr('aria-label', ariaLabel); - } - } + // 1. 獲取內容資訊 + var linkText = $a.text().replace(/\u00a0/g, '').trim(); + var $img = $a.find('img'); + var rawAlt = ($img.length > 0) ? ($img.attr('alt') || '').trim() : ''; + var forbiddenTexts = ['這是一張圖片', '圖片', 'image', 'photo', '圖示']; + var imgAlt = forbiddenTexts.includes(rawAlt) ? '' : rawAlt; - // ----- title 邏輯 ----- - if (!$a.attr('title')) { - let titleStr = ''; + var hasSrOnly = $a.find('.sr-only').length > 0 && $a.find('.sr-only').text().trim().length > 0; + var srOnlyText = hasSrOnly ? $a.find('.sr-only').text().trim() : ''; - if ($a.attr('target') === '_blank') { - titleStr += '在新視窗開啟 '; - } else if ($a.attr('target') === '_self') { - titleStr += '在本視窗開啟 '; - } + // 2. 移除空連結 + if (linkText === '' && $img.length === 0 && !hasSrOnly && !($a.attr('aria-label'))) { + $a.remove(); + return; + } - if ($a.find('img').length) { - titleStr = '這是一張照片'; - } else { - const text = $a.text().trim(); - if (text) { - titleStr += text; - } else if ($a.children('span').length === 1) { - titleStr += $a.children('span').text().trim(); - } - } + // 3. 準備視窗提示 + let windowTask = ($a.attr('target') === '_blank') ? '(在新視窗開啟)' : '(在本視窗開啟)'; - if (titleStr) { - $a.attr('title', titleStr); - } - } - }); - if (location.href.search('editmode=on') === -1){ - $('a').each(function () { - const $link = $(this); - const linkText = $link.text().trim(); + // 4. 核心邏輯判定 + + // 【情況 A:純圖片連結 (無文字)】 + if (linkText === "" && !hasSrOnly) { + if (imgAlt !== "") { + // 名字讓圖片 alt 說,title 只放動作提示 (避免重複) + $a.attr('title', windowTask); + $img.attr('alt', imgAlt); + } else { + let fallback = $a.attr('aria-label') || '連結'; + $a.attr('title', (fallback + ' ' + windowTask).trim()); + $img.attr('alt', fallback); + } + } + + // 【情況 B:有文字連結】 + else { + /** + * 智慧 Title 判斷: + * 1. 如果是標籤 (Class 含 label 或 tag) 或文字很短 (<= 6 字) + * -> Title 顯示:[文字內容] (動作提示) + * 2. 如果是長文章標題或一般長連結 + * -> Title 僅顯示:(動作提示) 以避免重複朗讀 + */ + var isTag = $a.hasClass('label') || $a.hasClass('tag') || $a.find('[class*="tag"]').length > 0 || $a.find('[class*="label"]').length > 0; + + if (linkText.length <= 6 || isTag) { + // 短文字或標籤:補全語意 + $a.attr('title', linkText + " " + windowTask); + } else { + // 長文字:精簡語意 + $a.attr('title', windowTask); + } - $link.find('img').each(function () { + // 符合規範:圖文並存時,圖片 alt 應為空值 + if ($img.length > 0) { + $img.attr('alt', ''); + } + } + + // 5. 最終清理 + $a.removeAttr('aria-label'); + $a.removeAttr('alt'); // a 標籤不應有 alt + + if ($img.length > 0 && forbiddenTexts.includes($img.attr('alt'))) { + $img.attr('alt', ''); + } + }); + } + + // 延遲執行 + setTimeout(fixAccessibilityAll, 500); +}); + + if (location.href.search('editmode=on') === -1) { + // 1. 處理圖片 alt 重複問題 (保持原邏輯但優化) + $('a').has('img').each(function () { + const $link = $(this); + const linkText = $link.text().trim(); + + $link.find('img').each(function () { const $img = $(this); const altText = $img.attr('alt')?.trim(); - // 如果圖片 alt 是空的,就略過(已符合) - if (altText === '') return; - - // 如果圖片 alt 等於文字內容,就將 alt 清空,避免重複 - if (altText === linkText) { - $img.attr('alt', ''); + if (altText && altText === linkText) { + $img.attr('alt', ''); } - }); - }); - $('a').each(function () { - const $a = $(this); - - // 取得可見文字(去掉空白) - const text = $a.text().replace(/\u00a0/g, '').trim(); - - // 是否有圖片 - const hasImg = $a.find('img').length > 0; - - // 若沒有文字、也沒有圖片 → 移除 - if (text === '' && !hasImg) { - $a.remove(); - } }); + }); } + $(function() { + function smartFixIcons() { + $('i').each(function() { + var $icon = $(this); + var $parent = $icon.parent(); - // 刪除banner-slide的空連結和空連結目標 - for(var i=0;i<$('.w-ba-banner__slide a').length;i++){ - if($('.w-ba-banner__slide a').eq(i).attr('href')=="") - $('.w-ba-banner__slide a').eq(i).removeAttr('href'); - if($('.w-ba-banner__slide a').eq(i).attr('target') == "") - $('.w-ba-banner__slide a').eq(i).removeAttr('target'); - }; - // 幫無標題之iframe加上title - for(var i=0;i<$('iframe').length;i++) - if($('iframe').eq(i).attr('title')=="" || $('iframe').eq(i).attr('title')== undefined ){ - if($('iframe').eq(i).attr('src').search('facebook') != -1 ) - $('iframe').eq(i).attr('title','facebook'); - else if($('iframe').eq(i).attr('src').search('google') != -1 ) - $('iframe').eq(i).attr('title','google'); - else if($('iframe').eq(i).attr('src').search('youtube') != -1 ) - $('iframe').eq(i).attr('title','youtube'); - else if($('iframe').eq(i).attr('src').search('twitframe') != -1 ) - $('iframe').eq(i).attr('title','twitter'); - else - $('iframe').eq(i).attr('title','unknown'); - }; - //button是空的就加上內容 - $('button').each(function() { - var $this = $(this); - var titleText = $this.attr('title') || ''; + // 1. 基本安全:所有圖示先對螢幕閱讀器隱藏 (避免讀出 Unicode 亂碼) + $icon.attr('aria-hidden', 'true'); - // 檢查 button 是否是空的(沒有可見文字或子元素) - if ($this.text().trim() === '' && !$this.children().length && titleText) { - // 新增隱藏的 span,內容為 title - $this.append('' + titleText + ''); + // 2. 檢查:如果已經有 aria-label 或旁邊已有 sr-only,就不重複處理 + if ($icon.attr('aria-label') || $icon.next('.sr-only').length > 0 || $parent.find('.sr-only').length > 0) { + return; + } + + var cls = ($icon.attr('class') || '').toLowerCase(); + var labelText = ''; + + // --- 策略 A:常見資訊型圖示 (自動識別內容意義) --- + if (cls.includes('calendar')) labelText = '日期:'; + else if (cls.includes('user') || cls.includes('male')) labelText = '發布者:'; + else if (cls.includes('tag')) labelText = '標籤:'; + else if (cls.includes('clock') || cls.includes('time')) labelText = '時間:'; + else if (cls.includes('map-marker') || cls.includes('location')) labelText = '地點:'; + else if (cls.includes('phone')) labelText = '電話:'; + else if (cls.includes('envelope') || cls.includes('mail')) labelText = '信箱:'; + else if (cls.includes('folder')) labelText = '分類:'; + else if (cls.includes('eye')) labelText = '瀏覽次數:'; + else if (cls.includes('download')) labelText = '下載檔案:'; + + // --- 策略 B:功能性按鈕 (如果 i 放在