From 5a3447785c510846efe1dc450bc6919d2fef2618 Mon Sep 17 00:00:00 2001 From: ken Date: Tue, 21 Jul 2026 19:01:25 +0800 Subject: [PATCH] update --- assets/javascripts/app.js | 1515 ++++++++++------- assets/stylesheets/template/base/_global.scss | 5 +- .../template/base/_go_back_top.scss | 4 +- .../stylesheets/template/base/_variables.scss | 2 +- .../stylesheets/template/layout/content.scss | 7 +- .../template/modules/ad_banner.scss | 8 +- .../template/modules/announcement.scss | 15 +- .../template/modules/archives.scss | 24 +- .../template/modules/web_resource.scss | 2 +- modules/ad_banner/_ad_banner_widget2.html.erb | 4 +- .../_annc_widget1.html.erb | 2 +- .../_annc_widget15.html.erb | 2 +- .../_annc_widget16.html.erb | 2 +- .../_annc_widget18.html.erb | 2 +- .../_annc_widget2.html.erb | 2 +- .../_annc_widget3.html.erb | 2 +- .../_annc_widget4.html.erb | 2 +- .../custom_gallery_index1.html.erb | 2 +- .../custom_gallery_index3.html.erb | 2 +- .../_event_news_widget1.html.erb | 2 +- .../_event_news_widget15.html.erb | 2 +- .../_event_news_widget2.html.erb | 2 +- .../_event_news_widget20.html.erb | 2 +- .../_event_news_widget21.html.erb | 2 +- .../_event_news_widget22.html.erb | 2 +- .../_event_news_widget3.html.erb | 2 +- .../_event_news_widget4.html.erb | 2 +- modules/gallery/gallery_index1.html.erb | 7 +- modules/gallery/gallery_index2.html.erb | 4 +- modules/gallery/gallery_index3.html.erb | 6 +- modules/gallery/gallery_index4.html.erb | 4 +- modules/gallery/gallery_index5.html.erb | 4 +- modules/gallery/gallery_index6.html.erb | 6 +- modules/member/show.html.erb | 2 +- 34 files changed, 929 insertions(+), 724 deletions(-) diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js index be3b4fc..6edb9fc 100644 --- a/assets/javascripts/app.js +++ b/assets/javascripts/app.js @@ -1,7 +1,36 @@ ;(function($, win, undefined) { // ECMAScript 5 嚴格模式 'use strict'; + $(function() { + var $signLanguageBox = $('.orbit-bar-search-sign-language'); + var $headerNav = $('.header-nav'); + var $target = $('.header-nav [accesskey="U"], .header-nav [accesskey="W"]'); + // 移除 color: inherit !important + $target.each(function() { + $(this)[0].style.removeProperty('color'); + }); + + function handleNavMove() { + var windowWidth = window.innerWidth; + + if (windowWidth > 768) { + if ($signLanguageBox.length && $signLanguageBox.find('[accesskey="U"], [accesskey="W"]').length === 0) { + $signLanguageBox.prepend($target); + } + } else { + if ($headerNav.length && $headerNav.find('[accesskey="U"], [accesskey="W"]').length === 0) { + $headerNav.append($target); + } + } + } + + handleNavMove(); + + $(window).on('resize', function() { + handleNavMove(); + }); + }); //header fixed在上方 function initdata1() { if ( $('.homebanner').length != 0) { @@ -291,6 +320,17 @@ }, 100); } }); + // ✅ Tab 鍵跳過 .navbar-toggle 時,觸發與點擊相同的收合邏輯 + $(document).on('focusout', '.mobile-menu', function(e) { + setTimeout(function() { + var $newFocus = $(document.activeElement); + // 焦點已離開 .mobile-menu 且選單是展開狀態 + if ($('.mobile-menu').hasClass('active') && $newFocus.closest('.mobile-menu').length === 0) { + // ✅ 直接 trigger click,與按下 .navbar-toggle 執行完全相同的動作 + $('.navbar-toggle').first().trigger('click'); + } + }, 50); + }); $('.mobile-menu1 > .menu-drop').click(function(){ var $that = $(this); @@ -590,7 +630,7 @@ } }); if (document.documentElement.lang === 'zh_tw') { - document.documentElement.lang = 'zh-Hant'; + document.documentElement.lang = 'zh-Hant-TW'; } //tab鍵按下 $(document).on('keydown', function(e) { @@ -703,20 +743,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('下一張'); @@ -760,6 +800,7 @@ $(document).ready(function() { removeEmptyTitles(); }); + // $(".w-annc__img-wrap a").each(function () { // var $this = $(this); // // 確保 內沒有文字節點 (避免重複添加) @@ -835,7 +876,7 @@ var isLinkImage = $parentA.length > 0 && $parentA.text().replace(/\u00a0/g, '').trim() === ""; // --- 1. 處理「裝飾性圖片」標註 --- - if (currentAlt === "announcement image" || currentAlt === "裝飾圖片" || currentTitle === "裝飾圖片") { + if (currentAlt === "announcement image" || currentAlt === "裝飾圖片" || currentTitle === "裝飾圖片" || currentAlt === "這是一張圖片" || currentTitle === "這是一張圖片") { $img.attr('alt', ''); $img.removeAttr('title'); return; @@ -880,78 +921,147 @@ setTimeout(fixImageAccessibility, 500); }); - // 有連結目的之所有a標籤的無障礙處理 - $(function() { - /** - * 全站無障礙 AA 級補強 (整合 HM1240400C 與 HM1240401C 規範) - */ - 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' : '連結', - openImg: isEn ? 'Open image' : '開啟圖片內容', - sort: isEn ? 'Sort' : '排序' - }; + /** + * 全站無障礙 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-TW'; + 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); + $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; + } - // 【條件判斷:若 a 標籤的 class 等於或包含 navbar-brand,則不執行此 function】 - if ($a.hasClass('navbar-brand')) { - return; - } - - var href = ($a.attr('href') || '').toLowerCase(); - if (!href || href.startsWith('javascript:')) return; + // A. 視窗動作規範 + var isNewWindow = ($a.attr('target') === '_blank'); + var windowTask = isNewWindow ? i18n.newWin : i18n.selfWin; - // 清理   與 空白 - var linkText = $a.text().replace(/\u00a0/g, '').trim(); - var $img = $a.find('img'); - var $icons = $a.find('i, svg'); // 偵測其他元素 (如 FontAwesome, SVG) - var currentTitle = ($a.attr('title') || '').trim(); - - // --- 【修正 1:隱藏空連結】 --- - if (!isEditMode && linkText === "" && $img.length === 0 && $icons.length === 0) { - $a.hide(); - return; - } + // 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:符合 HM1240401C 的文字與標題防禦】 --- - // 若連結文字為空、或文字內容為無效的 URL 路徑,自動補上語意文字 - if (linkText === "" || linkText.startsWith('/') || linkText.includes('?')) { - var accessibleText = i18n.link; // 預設名稱 - - // 智慧判斷:若為排序連結,可顯示為「排序」 - if (href.includes('sort')) { - accessibleText = i18n.sort; + // 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); } - var $span = $a.find('span'); - if ($span.length > 0) { - $span.text(accessibleText); - } else { - $a.append('' + accessibleText + ''); - $span = $a.find('span').last(); - } - - // 套用視覺隱藏但螢幕閱讀器可讀取之樣式 $span.css({ 'display': 'inline-block', 'position': 'absolute', @@ -964,206 +1074,221 @@ 'white-space': 'nowrap', 'border': '0' }); - - linkText = accessibleText; // 更新變數以便後續比對 - } - - // 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') || - currentTitle.includes('/uploads/'); - - // 如果 title 是 URL,視為壞標籤並重置 - if (currentTitle.startsWith('/') || currentTitle.includes('?')) { - currentTitle = ""; - } - - // D. 處理【HM1240400C】:圖片與文字毗鄰時,替代文字只能有一份 - if (($img.length > 0 || $icons.length > 0) && linkText !== "") { - if ($img.length > 0) { - // 強制圖片設為裝飾性 - $img.attr('alt', ''); - } - } - - // 【調整】將隱藏 span 邏輯移出判斷,讓沒有圖片的單純連結也能轉換為無障礙樣式 - 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. 重新計算標題與替代文字 (針對不同情境) - 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 if (linkText.length <= 8) { - $a.attr('title', linkText + " " + windowTask); - } else { - $a.attr('title', windowTask); - } - } - } - - // 【HM1240401C 補強】若連結包含其他多媒體內容 (如 i 標籤、SVG),需補齊 title 屬性 - var hasOtherContent = ($img.length > 0 || $icons.length > 0); - if (hasOtherContent && currentTitle === "") { - var newTitle = linkText + " " + windowTask; - $a.attr('title', newTitle.trim()); - } - - // F. 最終清理:移除冗餘 label - $a.removeAttr('aria-label'); - }); + } } - // 延遲執行確保 DOM 載入完成 - setTimeout(function() { - fixAccessibilityAll(); - }, 800); + // 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 相同,則只保留開窗提示 + if ( + (titleWithoutWindow === linkText && linkText !== i18n.link) || + (imgAltOriginal !== '' && titleWithoutWindow === imgAltOriginal) + ) { + $a.attr('title', windowTask); + } + + // ✅ 最終清理:若 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', ''); - // } - // }); - // }); - // } - $(function() { - function smartFixIcons() { - var isEn = $('html').attr('lang') === 'en'; - - var labels = { - calendar : isEn ? 'Date: ' : '日期:', - user : isEn ? 'Author: ' : '發布者:', - tag : isEn ? 'Tag: ' : '標籤:', - clock : isEn ? 'Time: ' : '時間:', - location : isEn ? 'Location: ' : '地點:', - phone : isEn ? 'Phone: ' : '電話:', - envelope : isEn ? 'Email: ' : '信箱:', - folder : isEn ? 'Category: ' : '分類:', - eye : isEn ? 'Views: ' : '瀏覽次數:', - download : isEn ? 'Download: ' : '下載檔案:', - search : isEn ? 'Search' : '搜尋', - bars : isEn ? 'Menu' : '選單', - print : isEn ? 'Print this page': '列印此頁', - share : isEn ? 'Share' : '分享至社群', - close : isEn ? 'Close' : '關閉視窗' - }; - - $('i').each(function() { - var $icon = $(this); - var $parent = $icon.parent(); - - // 1. 所有圖示先對螢幕閱讀器隱藏 - $icon.attr('aria-hidden', 'true'); - - // 特判:.close-screen-btn 內的圖示,移除無關的 sr-only 並設正確 aria-label - if ($parent.hasClass('close-screen-btn')) { - $parent.find('.sr-only').remove(); - $parent.attr('aria-label', '關閉公告視窗'); - return; - } - - // 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 = labels.calendar; - else if (cls.includes('user') || cls.includes('male')) labelText = labels.user; - else if (cls.includes('tag')) labelText = labels.tag; - else if (cls.includes('clock') || cls.includes('time')) labelText = labels.clock; - else if (cls.includes('map-marker') || cls.includes('location')) labelText = labels.location; - else if (cls.includes('phone')) labelText = labels.phone; - else if (cls.includes('envelope') || cls.includes('mail')) labelText = labels.envelope; - else if (cls.includes('folder')) labelText = labels.folder; - else if (cls.includes('eye')) labelText = labels.eye; - else if (cls.includes('download')) labelText = labels.download; - - // --- 策略 B:功能性按鈕 --- - var $container = $icon.closest('a, button'); - if ($container.length > 0 && $container.text().trim() === '') { - var btnTitle = $container.attr('title'); - if (btnTitle) labelText = btnTitle; - else if (cls.includes('search')) labelText = labels.search; - else if (cls.includes('bars') || cls.includes('navicon')) labelText = labels.bars; - else if (cls.includes('print')) labelText = labels.print; - else if (cls.includes('share')) labelText = labels.share; - else if (cls.includes('close') || cls.includes('times')) labelText = labels.close; - } - - // --- 3. 執行補強 --- - if (labelText !== '') { - if ($container.length > 0 && $container.text().trim() === '') { - $container.attr('aria-label', labelText); - } else { - $icon.after('' + labelText + ''); - } - } - }); + $('a.i-archive__file-name').each(function () { + var $a = $(this); + var isNewWindow = ($a.attr('target') === '_blank'); + $a.attr('title', isNewWindow ? i18n.newWin : i18n.selfWin); + }); } - setTimeout(smartFixIcons, 500); - }); + // ✅ 延遲 800ms 確保所有其他 function 執行完畢後才處理 + setTimeout(function() { + fixAccessibilityAll(); + }, 800); +}); + + +$(function() { + function smartFixIcons() { + var isEn = $('html').attr('lang') === 'en'; + + var labels = { + calendar : isEn ? 'Date: ' : '日期:', + user : isEn ? 'Author: ' : '發布者:', + tag : isEn ? 'Tag: ' : '標籤:', + clock : isEn ? 'Time: ' : '時間:', + location : isEn ? 'Location: ' : '地點:', + phone : isEn ? 'Phone: ' : '電話:', + envelope : isEn ? 'Email: ' : '信箱:', + folder : isEn ? 'Category: ' : '分類:', + eye : isEn ? 'Views: ' : '瀏覽次數:', + download : isEn ? 'Download: ' : '下載檔案:', + search : isEn ? 'Search' : '搜尋', + bars : isEn ? 'Menu' : '選單', + print : isEn ? 'Print this page' : '列印此頁', + share : isEn ? 'Share' : '分享至社群', + close : isEn ? 'Close window' : '關閉視窗', + closePopup : isEn ? 'Close announcement' : '關閉公告視窗', + closeGallery: isEn ? 'Close gallery' : '關閉相簿', + toggleDesc : isEn ? 'Show or hide image description' : '顯示或隱藏圖片說明', + themeSwitch : isEn ? 'Switch gallery theme': '切換相簿主題', + showOriginal: isEn ? 'Show original image' : '顯示原始圖片' + }; + + $('i').each(function() { + var $icon = $(this); + var $parent = $icon.parent(); + + // 1. 所有圖示先對螢幕閱讀器隱藏 + $icon.attr('aria-hidden', 'true'); + + // 特判:.close-screen-btn 內的圖示,移除無關的 sr-only 並設正確 aria-label + if ($parent.hasClass('close-screen-btn')) { + $parent.find('.sr-only').remove(); + $parent.attr('aria-label', labels.closePopup); + if ($icon.next('.sr-only').length === 0) { + $icon.after('' + labels.closePopup + ''); + } + return; + } + + // 特判:.gallery-close 內的圖示,移除錯誤的 sr-only 並補正確說明 + if ($parent.closest('.gallery-close').length > 0) { + $parent.closest('.gallery-close').find('.sr-only').remove(); + $parent.closest('.gallery-close').attr('aria-label', labels.closeGallery); + $parent.closest('.gallery-close').attr('role', 'button'); + $parent.closest('.gallery-close').attr('tabindex', '0'); + if ($icon.next('.sr-only').length === 0) { + $icon.after('' + labels.closeGallery + ''); + } + return; + } + + // 特判:.gallery-toggle-desc 補說明 + if ($parent.closest('.gallery-toggle-desc').length > 0) { + var $toggleBtn = $parent.closest('.gallery-toggle-desc'); + if (!$toggleBtn.attr('aria-label')) { + $toggleBtn.attr('aria-label', labels.toggleDesc); + $toggleBtn.attr('role', 'button'); + $toggleBtn.attr('tabindex', '0'); + } + if ($icon.next('.sr-only').length === 0) { + $icon.after('' + labels.toggleDesc + ''); + } + return; + } + + // 特判:.gallery-theme-switch 補說明 + if ($parent.closest('.gallery-theme-switch').length > 0) { + var $themeBtn = $parent.closest('.gallery-theme-switch'); + if (!$themeBtn.attr('aria-label')) { + $themeBtn.attr('aria-label', labels.themeSwitch); + $themeBtn.attr('role', 'button'); + $themeBtn.attr('tabindex', '0'); + } + if ($icon.next('.sr-only').length === 0) { + $icon.after('' + labels.themeSwitch + ''); + } + return; + } + + // 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 = labels.calendar; + else if (cls.includes('user') || cls.includes('male')) labelText = labels.user; + else if (cls.includes('tag')) labelText = labels.tag; + else if (cls.includes('clock') || cls.includes('time')) labelText = labels.clock; + else if (cls.includes('map-marker') || cls.includes('location')) labelText = labels.location; + else if (cls.includes('phone')) labelText = labels.phone; + else if (cls.includes('envelope') || cls.includes('mail')) labelText = labels.envelope; + else if (cls.includes('folder')) labelText = labels.folder; + else if (cls.includes('eye')) labelText = labels.eye; + else if (cls.includes('download')) labelText = labels.download; + + // --- 策略 B:功能性按鈕 --- + var $container = $icon.closest('a, button'); + if ($container.length > 0 && $container.text().trim() === '') { + var btnTitle = $container.attr('title'); + if (btnTitle) labelText = btnTitle; + else if (cls.includes('search')) labelText = labels.search; + else if (cls.includes('bars') || cls.includes('navicon')) labelText = labels.bars; + else if (cls.includes('print')) labelText = labels.print; + else if (cls.includes('share')) labelText = labels.share; + else if (cls.includes('close') || cls.includes('times')) labelText = labels.close; + else if (cls.includes('image') || cls.includes('photo')) labelText = labels.showOriginal; + } + + // --- 3. 執行補強 --- + if (labelText !== '') { + $icon.after('' + labelText + ''); + } + }); + } + + setTimeout(smartFixIcons, 500); +}); // 刪除banner-slide的空連結和空連結目標 for(var i=0;i<$('.w-ba-banner__slide a').length;i++){ if($('.w-ba-banner__slide a').eq(i).attr('href')=="") @@ -1213,9 +1338,9 @@ // 已有 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 } }); @@ -1224,7 +1349,7 @@ 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); }); @@ -1235,9 +1360,9 @@ // 已有 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 } }); @@ -1246,7 +1371,7 @@ 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); }); @@ -1388,92 +1513,7 @@ 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'); @@ -1539,62 +1579,222 @@ // 延遲執行,確保動態產生的選單也能被補強 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() { @@ -1616,6 +1816,15 @@ // 執行處理 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(); @@ -1964,6 +2173,14 @@ $(document).ready(function() { // if($('.show-announcement').hasClass('show-announcement')) { // $('.').css('', ''); // } + $(function() { + var $headerNav = $('.header-nav'); + $headerNav.contents().each(function() { + if (this.nodeType === 3 && this.nodeValue.trim() === '|') { + $(this).remove(); + } + }); + }); $('#main-nav a[title="首頁"]').each(function(){ $(this).html(''); }); @@ -2211,275 +2428,162 @@ $(document).ready(function() { init(); }); -// 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'); - } +//post +$(document).ready(function () { + setTimeout(function () { + $('iframe.twitter-share-button, iframe.twitter-tweet-button').each(function () { + $(this).attr('title', '分享至 X 在新視窗開啟'); }); + }, 1500); +}); +$(function() { + function bindIframeFocus() { + var $iframe = $('.twitter-share-button'); + if ($iframe.length === 0) return; - // 強制偵測:在 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'); - } - }); + $iframe.each(function() { + var $wrap = $(this).closest('.tw-share-button'); - // --- 【修正重點 2】處理選單內第一個元素的 Shift+Tab --- - $firstInput.on('keydown', function(e) { - if (e.shiftKey && e.keyCode === 9) { // 在第一個輸入框按 Shift + Tab - // 讓它自然回到 Label,Label 的 focusin 會接手處理收合 - // 這裡不做額外動作,交給上面的 focusin 邏輯 - } - }); + // 讓外層可以被 tab 到並顯示焦點框 + $wrap.attr('tabindex', '-1'); - // --- 【修正重點 3】處理離開大區塊(往後 Tab)的狀態清除 --- - $searchArea.on('focusout', function() { - var $thisArea = $(this); + $(window).on('blur.twitterFocus', function() { 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); + if (document.activeElement && + $(document.activeElement).hasClass('twitter-share-button')) { + $wrap.css({ + 'outline': '3px solid #005fcc', + 'outline-offset': '2px', + 'border-radius': '2px' + }); + } + }, 100); + }); + + $(window).on('focus.twitterFocus', function() { + $wrap.css({ + 'outline': '', + 'outline-offset': '' + }); + }); }); + } - // 點擊行為 - $orbitLabel.on('click', function() { - var isOpen = $searchArea.hasClass('show'); - $searchArea.toggleClass('show', !isOpen); - $(this).attr('aria-expanded', !isOpen); + // 用 MutationObserver 等 iframe 被 Twitter script 插入後才綁定 + var observer = new MutationObserver(function(mutations) { + if ($('.twitter-share-button').length > 0) { + bindIframeFocus(); + observer.disconnect(); // 綁定成功後停止監聽 + } + }); + + observer.observe(document.body, { + childList: true, + subtree: true + }); + + // 保險:2秒後強制執行一次 + setTimeout(bindIframeFocus, 1000); +}); +//orbitbarlogo無障礙 +$(function() { + var $logo = $('.orbit-bar-logo'); + var $inner = $logo.contents().not('p'); + + var $span = $('').addClass('orbit-bar-logo').append($inner); + $logo.replaceWith($span); +}); +//orbitbar登入無障礙 +$(function() { + var $loginWindow = $('.login-window'); + var $checkbox = $('#open-orbit-login'); + + // login-window 顯示時,焦點移到 label.close + $checkbox.on('change', function() { + if ($(this).is(':checked')) { + setTimeout(function() { + $('.login-window .login-header label.close').focus(); + }, 50); + } + }); + + // login-window 失去焦點時,關閉並還原焦點 + $loginWindow.on('focusout', function() { + var $thisWindow = $(this); + setTimeout(function() { + // document.hasFocus() 為 false 代表焦點移到瀏覽器外(開發者工具、右鍵選單等),不關閉 + if (!document.hasFocus()) return; + + if (!$thisWindow.is(':focus-within') && $checkbox.is(':checked')) { + $(".orbit-bar-logo").one("focusin", function() { + if (window.orbit_login_button) { + window.orbit_login_button.focus(); + } + }); + $checkbox.click(); + } + }, 500); + }); +}); +//gallery層級問題 +$(function() { + var target = document.getElementById('gallery-theater-stage'); + if (!target) return; + + // 頁面載入時若已存在 #gallery-theater-stage,則還原 z-index + $('.verticalhome').css('z-index', 'auto'); + + var observer = new MutationObserver(function() { + var display = target.style.display; + if (display === 'block') { + $('.verticalhome').css('z-index', '2000'); + } else if (display === 'none') { + $('.verticalhome').css('z-index', 'auto'); + } + }); + + observer.observe(target, { + attributes : true, + attributeFilter: ['style'] + }); +}); +$(document).ready(function() { + + function removeFakeLinks() { + $('a.fake_link').remove(); + } + + // 初始執行一次 + removeFakeLinks(); + + // Shift+Tab 時也執行 + $(document).on('keydown', function(e) { + if (e.key === 'Tab' && e.shiftKey) { + removeFakeLinks(); + } + }); + + // MutationObserver 監聽 DOM 變化,fake_link 一出現就移除 + var observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + mutation.addedNodes.forEach(function(node) { + // 直接是 fake_link + if ($(node).is('a.fake_link')) { + $(node).remove(); + } + // 或其子元素內含 fake_link + if ($(node).find) { + $(node).find('a.fake_link').remove(); + } + }); }); + }); - // RWD 位置搬移 - function moveSearch() { - if ($(window).width() < 767) { - $searchArea.insertAfter('label[for="open-orbit-nav"]'); - } else { - $searchArea.appendTo('.orbit-bar-inner'); - } - } - moveSearch(); - $(window).resize(moveSearch); -}); + observer.observe(document.body, { + childList: true, + subtree: true + }); -// 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 補上可聚焦 - // 桌面版 + 手機版都處理 - // ============================================= - 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( - '' + - activeText + - '' - ); - } - }); - - // ============================================= - // 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(); - }); - - // ✅ 新增 GN1210100E:Enter / 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 () { @@ -2638,6 +2742,9 @@ $(function() { var target = document.getElementById('gallery-theater-stage'); if (!target) return; + // 頁面載入時若已存在 #gallery-theater-stage,則還原 z-index + $('.verticalhome').css('z-index', 'auto'); + var observer = new MutationObserver(function() { var display = target.style.display; if (display === 'block') { @@ -2689,6 +2796,94 @@ $(document).ready(function() { subtree: true }); +}); +//萬用表格無障礙 +function fixSortLinkA11y() { + $('a').filter(function () { + return $(this).find('.universal-th-icon').length > 0; + }).each(function () { + var $link = $(this); + + // === Step 1: 移除 display:none 的 span === + $link.find('span').each(function () { + if ($(this).css('display') === 'none' || $(this).attr('style') && $(this).attr('style').indexOf('display: none') !== -1) { + $(this).remove(); + } + }); + + // === Step 2: 取得 aria-label === + var ariaLabel = $link.attr('aria-label') || ''; + + // 若 aria-label 空白或含未替換模板變數,從旁邊 .universal-th-text 補 + if (!ariaLabel || ariaLabel.indexOf('{{') !== -1) { + var $th = $link.closest('th, div[class*="col-"]'); + var colName = $th.find('.universal-th-text').text().trim(); + ariaLabel = colName ? '重新排序' + colName : '排序'; + $link.attr('aria-label', ariaLabel); + } + + // === Step 3: 補上 title 屬性 === + if (!$link.attr('title')) { + $link.attr('title', ariaLabel + '(在本視窗開啟)'); + } + + // === Step 4: 確保圖示有 aria-hidden === + $link.find('.universal-th-icon').attr('aria-hidden', 'true'); + + // === Step 5: 補上 visually-hidden 連結文字 === + if ($link.find('.visually-hidden').length === 0) { + $link.append('' + ariaLabel + ''); + } + }); +} +function fixSearchInputA11y() { + $('input[type="search"], input[type="text"]').each(function () { + var $input = $(this); + + // 已有對應 label 就跳過 + var inputId = $input.attr('id'); + if (inputId && $('label[for="' + inputId + '"]').length) return; + + // 已有 aria-label / aria-labelledby / title 就跳過 + if ($input.attr('aria-label') || $input.attr('aria-labelledby') || $input.attr('title')) return; + + // 從 placeholder 取得說明文字 + var placeholder = $input.attr('placeholder') || ''; + + // 從最近的 th 或欄位標題取得欄位名稱 + var colName = ''; + var $th = $input.closest('th, div[class*="col-"]'); + if ($th.length) { + colName = $th.find('.universal-th-text').text().trim(); + } + + // 組合標籤文字 + var label = ''; + if (colName && placeholder) { + label = colName + '搜尋'; + } else if (colName) { + label = colName + '搜尋'; + } else if (placeholder) { + label = placeholder; + } else { + label = '搜尋關鍵字'; + } + + $input.attr('aria-label', label); + $input.attr('title', label); + }); +} + +$(document).ready(function () { + setTimeout(function () { + fixSortLinkA11y(); + fixSearchInputA11y(); + }, 500); +}); +$(document).ready(function () { + setTimeout(function () { + $('.dtr-control').removeAttr('tabindex'); + }, 500); }); // 執行 member等高計算,目前改用flexbox故mark掉 by ika 20160105 // $(window).load(function() { diff --git a/assets/stylesheets/template/base/_global.scss b/assets/stylesheets/template/base/_global.scss index c84953d..8396585 100644 --- a/assets/stylesheets/template/base/_global.scss +++ b/assets/stylesheets/template/base/_global.scss @@ -4,13 +4,16 @@ @import "variables"; .fa-classic, .fa-regular, .fa-solid, .far, .fas ,.fa{ - font-family: var(--fa-style-family, "FontAwesome"); + font-family: "FontAwesome"; } #orbit-bar .orbit-bar-inner > label:focus, #orbit-bar .orbit-bar-inner > label.focus{ .orbit-bar-search-sign-language{ display: block } } +#orbit-bar .orbit-bar-menu .orbit-bar-logo{ + cursor: unset!important; +} .login-btn:focus { outline: 0.3125em auto -webkit-focus-ring-color !important; diff --git a/assets/stylesheets/template/base/_go_back_top.scss b/assets/stylesheets/template/base/_go_back_top.scss index 036bb15..bbba894 100644 --- a/assets/stylesheets/template/base/_go_back_top.scss +++ b/assets/stylesheets/template/base/_go_back_top.scss @@ -15,10 +15,8 @@ font-size: 0.750em; border-radius: 0.125em; z-index: 1050; - opacity: .7; &:hover { - background:$theme-color-second; - opacity:1; + background:#005380; } } diff --git a/assets/stylesheets/template/base/_variables.scss b/assets/stylesheets/template/base/_variables.scss index 962e9e5..1caa4c5 100644 --- a/assets/stylesheets/template/base/_variables.scss +++ b/assets/stylesheets/template/base/_variables.scss @@ -19,7 +19,7 @@ $theme-color-main: #333333; $theme-color-second:#007bbd; $theme-color-third: #007bbd; $theme-color-green: #007bbd; -$theme-color-hover:#27a1e2; +$theme-color-hover:#016ea9; .fa, .fa-classic, .fa-regular, .fa-solid, .far, .fas { font-family: "Font Awesome 6 Free", FontAwesome; diff --git a/assets/stylesheets/template/layout/content.scss b/assets/stylesheets/template/layout/content.scss index 09a94eb..5350f5c 100644 --- a/assets/stylesheets/template/layout/content.scss +++ b/assets/stylesheets/template/layout/content.scss @@ -1,6 +1,11 @@ @charset "utf-8"; @import "../initial"; +.line-it-button{ + .label{ + color: #333!important; + } +} .col-lg-1, .col-lg-10, .col-lg-11, .col-lg-12, .col-lg-2, .col-lg-3, .col-lg-4, .col-lg-5, .col-lg-6, .col-lg-7, .col-lg-8, .col-lg-9, .col-md-1, .col-md-10, .col-md-11, .col-md-12, .col-md-2, .col-md-3, .col-md-4, .col-md-5, .col-md-6, .col-md-7, .col-md-8, .col-md-9, .col-sm-1, .col-sm-10, .col-sm-11, .col-sm-12, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-xs-1, .col-xs-10, .col-xs-11, .col-xs-12, .col-xs-2, .col-xs-3, .col-xs-4, .col-xs-5, .col-xs-6, .col-xs-7, .col-xs-8, .col-xs-9{ @media(max-width: $screen-xs){ padding: 0; @@ -306,7 +311,7 @@ --wp--preset--color--light-green-cyan: #7bdcb5; --wp--preset--color--vivid-green-cyan: #00d084; --wp--preset--color--pale-cyan-blue: #8ed1fc; - --wp--preset--color--vivid-cyan-blue: #0693e3; + --wp--preset--color--vivid-cyan-blue: #006199; --wp--preset--color--vivid-purple: #9b51e0; --wp--preset--color--vk-color-custom-1: #35933a; --wp--preset--color--vk-color-custom-2: #4e7a4e; diff --git a/assets/stylesheets/template/modules/ad_banner.scss b/assets/stylesheets/template/modules/ad_banner.scss index 2bfed74..f4880f3 100644 --- a/assets/stylesheets/template/modules/ad_banner.scss +++ b/assets/stylesheets/template/modules/ad_banner.scss @@ -30,9 +30,11 @@ ul.button-mid{ } } } -ul.button-mid{ - margin:0; - z-index: 201; +.button-mid { + position: absolute; + width: 100%; + height: 0; + top: 50%; } .banner-pager .active-slide button{ background: $theme-color-second!important; diff --git a/assets/stylesheets/template/modules/announcement.scss b/assets/stylesheets/template/modules/announcement.scss index 1eaca08..f459dde 100644 --- a/assets/stylesheets/template/modules/announcement.scss +++ b/assets/stylesheets/template/modules/announcement.scss @@ -123,7 +123,7 @@ // display: inline-block; // margin-right: 0.2em; @extend .i-title; - color: #0693e3; + color: #006199; font-weight: normal; display: flex; align-items: center; @@ -1736,7 +1736,7 @@ display: none; } .w-annc__meta i{ - color: #0693e3!important; + color: #006199!important; } .w-annc__category-wrap{ display: none!important; @@ -2590,12 +2590,6 @@ .i-annc__entry-title { margin-bottom: 0; margin-top: 0; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - text-overflow: ellipsis; - // clear: both; } .i-annc__title { @@ -2603,6 +2597,11 @@ color: $theme-color-main; text-decoration: none; @extend .i-title; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + text-overflow: ellipsis; + overflow: hidden; &:hover { color: $theme-color-second; } diff --git a/assets/stylesheets/template/modules/archives.scss b/assets/stylesheets/template/modules/archives.scss index 23d3f5a..95b8d67 100644 --- a/assets/stylesheets/template/modules/archives.scss +++ b/assets/stylesheets/template/modules/archives.scss @@ -177,18 +177,18 @@ .i-archive-title { @extend .unity-title; } -.link { background-color: #1368d4 !important; } /* 對比 4.6:1 */ -.txt { background-color: #3a8a40 !important; } /* 對比 4.6:1 */ -.xlsx { background-color: #9e3050 !important; } /* 對比 4.6:1 */ -.pdf { background-color: #2a7d36 !important; } /* 對比 4.6:1 */ -.docx { background-color: #5e46a0 !important; } /* 對比 4.6:1 */ -.doc { background-color: #1368d4 !important; } /* 對比 4.6:1 */ -.pptx { background-color: #3d4aa0 !important; } /* 對比 4.6:1 */ -.jpg { background-color: #8f3333 !important; } /* 對比 4.6:1 */ -.zip { background-color: #8a6400 !important; } /* 對比 4.6:1 */ -.rar { background-color: #9e5000 !important; } /* 對比 4.6:1 */ -.xls { background-color: #3a8a40 !important; } /* 對比 4.6:1 */ -.odt { background-color: #767676 !important; } /* 對比 4.6:1 */ +.link { background-color: #1368d4 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.txt { background-color: #3a8a40 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.xlsx { background-color: #9e3050 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.pdf { background-color: #2a7d36 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.docx { background-color: #5e46a0 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.doc { background-color: #1368d4 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.pptx { background-color: #3d4aa0 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.jpg { background-color: #8f3333 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.zip { background-color: #8a6400 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.rar { background-color: #9e5000 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.xls { background-color: #3a8a40 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.odt { background-color: #767676 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ .table>caption+thead>tr:first-child>td, .table>caption+thead>tr:first-child>th, .table>colgroup+thead>tr:first-child>td, .table>colgroup+thead>tr:first-child>th, .table>thead:first-child>tr:first-child>td, .table>thead:first-child>tr:first-child>th{ // border-top: 0.0625em solid #ddd; } diff --git a/assets/stylesheets/template/modules/web_resource.scss b/assets/stylesheets/template/modules/web_resource.scss index 39b9c1b..73938f5 100644 --- a/assets/stylesheets/template/modules/web_resource.scss +++ b/assets/stylesheets/template/modules/web_resource.scss @@ -416,7 +416,7 @@ .index-context { display: inline-block; // margin: 0 0 0.625em 2em; - color: darken($theme-gray-light, 20%); + color: #5c5c5c; } } diff --git a/modules/ad_banner/_ad_banner_widget2.html.erb b/modules/ad_banner/_ad_banner_widget2.html.erb index e7c9f79..70ef492 100644 --- a/modules/ad_banner/_ad_banner_widget2.html.erb +++ b/modules/ad_banner/_ad_banner_widget2.html.erb @@ -29,7 +29,9 @@ - +