diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js index 3941b3d..64b49b7 100644 --- a/assets/javascripts/app.js +++ b/assets/javascripts/app.js @@ -292,69 +292,103 @@ } }, - ClickMenuHandler: function() { - // 處理主選單切換(漢堡 icon) - $(document).on('click', '.navbar-toggle', function (e) { - e.preventDefault(); + ClickMenuHandler: function() { + // 處理主選單切換(漢堡 icon) + $(document).on('click', '.navbar-toggle', function (e) { + e.preventDefault(); - // 確保 .navbar-toggle 放到 .modules-menu 後面 - $('.mobile-menu').each(function () { - var $menu = $(this); - if ($menu.find('.modules-menu').length && !$menu.find('.modules-menu + .navbar-toggle').length) { - $menu.find('.modules-menu').after($menu.find('.navbar-toggle')); + // 確保 .navbar-toggle 放到 .modules-menu 後面 + $('.mobile-menu').each(function () { + var $menu = $(this); + if ($menu.find('.modules-menu').length && !$menu.find('.modules-menu + .navbar-toggle').length) { + $menu.find('.modules-menu').after($menu.find('.navbar-toggle')); + } + }); + + $('.mobile-menu').toggleClass('active'); + $('body').toggleClass('noscroll'); + + // ★ 修正:依據 active 狀態決定 collapsed 的加/移除 + if ($('.mobile-menu').hasClass('active')) { + $('.mobile-menu .navbar-toggle').removeClass('collapsed'); // 打開 → 叉叉 + } else { + $('.mobile-menu .navbar-toggle').addClass('collapsed'); // 關閉 → 三條橫線 + } + + // 關閉所有下拉選單 + $('.mobile-menu1 > ul, .mobile-menu2 > ul').slideUp(500); + $('.mobile-menu1 > .menu-drop, .mobile-menu2 > .menu-drop').removeClass('opened'); + + // 無障礙:聚焦第一個互動元素 + if ($('.mobile-menu').hasClass('active')) { + setTimeout(function () { + $('.modules-menu').find('input, button, select, textarea, a').first().focus(); + }, 100); } }); - $('.mobile-menu').toggleClass('active'); - $('body').toggleClass('noscroll'); - $('.mobile-menu .navbar-toggle').removeClass('collapsed'); + // ✅ Tab 鍵跳過 .mobile-menu 時,觸發收合邏輯 + $(document).on('focusout', '.mobile-menu', function(e) { + setTimeout(function() { + var $newFocus = $(document.activeElement); - // 關閉所有下拉選單 - $('.mobile-menu1 > ul, .mobile-menu2 > ul').slideUp(500); - $('.mobile-menu1 > .menu-drop, .mobile-menu2 > .menu-drop').removeClass('opened'); + // 焦點在 body 時代表滑鼠正在點擊中,不處理 + if ($newFocus.is('body')) return; - // 無障礙:聚焦第一個互動元素 - if ($('.mobile-menu').hasClass('active')) { - setTimeout(function () { - $('.modules-menu').find('input, button, select, textarea, a').first().focus(); - }, 100); - } - }); + if ($('.mobile-menu').hasClass('active') && $newFocus.closest('.mobile-menu').length === 0) { - $('.mobile-menu1 > .menu-drop').click(function(){ - var $that = $(this); - var opencheck1 = $that.hasClass('opened'); - if ( opencheck1 == 0 ) { - $('.mobile-menu1 > ul').not($that.siblings('ul')).slideUp(500); - $('.mobile-menu1 > .menu-drop').not($that).removeClass('opened'); - $('.mobile-menu2 > ul').slideUp(500); - $('.mobile-menu2 > .menu-drop').removeClass('opened'); - $that.siblings('ul').slideDown(500); - $that.addClass('opened'); + var $btn = $('.navbar-toggle').first(); - } else if (opencheck1 == 1) { - $that.siblings('ul').slideUp(500); - $('.mobile-menu2 > ul').slideUp(500); - $('.mobile-menu2 > .menu-drop').removeClass('opened'); - $that.removeClass('opened'); + if ($btn.attr('data-bs-toggle')) { + var target = $btn.attr('data-bs-target'); + var bsCollapse = window.bootstrap && bootstrap.Collapse.getInstance($(target)[0]); + if (bsCollapse) bsCollapse.hide(); + $('.mobile-menu').removeClass('active'); + $('body').removeClass('noscroll'); + $('.mobile-menu .navbar-toggle').addClass('collapsed'); + $('.mobile-menu1 > ul, .mobile-menu2 > ul').slideUp(500); + $('.mobile-menu1 > .menu-drop, .mobile-menu2 > .menu-drop').removeClass('opened'); + } else { + $btn.trigger('click'); + } + } + }, 50); + }); - } - }) + $('.mobile-menu1 > .menu-drop').click(function(){ + var $that = $(this); + var opencheck1 = $that.hasClass('opened'); + if ( opencheck1 == 0 ) { + $('.mobile-menu1 > ul').not($that.siblings('ul')).slideUp(500); + $('.mobile-menu1 > .menu-drop').not($that).removeClass('opened'); + $('.mobile-menu2 > ul').slideUp(500); + $('.mobile-menu2 > .menu-drop').removeClass('opened'); + $that.siblings('ul').slideDown(500); + $that.addClass('opened'); - $('.mobile-menu2 > .menu-drop').click(function(){ - var $that = $(this); - var opencheck2 = $that.hasClass('opened'); - if ( opencheck2 == 0 ) { - $('.mobile-menu2 > ul').not($that.siblings('ul')).slideUp(500); - $('.mobile-menu2 > .menu-drop').not($that).removeClass('opened'); - $that.siblings('ul').slideDown(500); - $that.addClass('opened'); - } else if (opencheck2 == 1) { - $that.siblings('ul').slideUp(500); - $that.removeClass('opened'); - } - }) - } + } else if (opencheck1 == 1) { + $that.siblings('ul').slideUp(500); + $('.mobile-menu2 > ul').slideUp(500); + $('.mobile-menu2 > .menu-drop').removeClass('opened'); + $that.removeClass('opened'); + + } + }) + + $('.mobile-menu2 > .menu-drop').click(function(){ + var $that = $(this); + var opencheck2 = $that.hasClass('opened'); + if ( opencheck2 == 0 ) { + $('.mobile-menu2 > ul').not($that.siblings('ul')).slideUp(500); + $('.mobile-menu2 > .menu-drop').not($that).removeClass('opened'); + $that.siblings('ul').slideDown(500); + $that.addClass('opened'); + } else if (opencheck2 == 1) { + $that.siblings('ul').slideUp(500); + $that.removeClass('opened'); + } + }) + } }; // 把orbit物件加到window物件裡面並改名為ORBITFRONT來減少名稱衝突的機會 @@ -481,20 +515,28 @@ }); //播放驗證碼語音 $(function () { - $('.ask-question') - .find('.controls button.fas.fa-volume-up') - .each(function () { - const $btn = $(this); + var pageLang = ($('html').attr('lang') || 'zh-Hant').toLowerCase(); + var isEn = pageLang.startsWith('en'); + var label = isEn ? 'Play Captcha Voice' : '播放驗證碼語音'; - // 已經補過就不重複處理 - if ($btn.attr('aria-label')) return; + $('.ask-question') + .find('.controls button.fas.fa-volume-up') + .each(function () { + var $btn = $(this); - $btn.attr({ - 'aria-label': '播放驗證碼語音', - 'aria-controls': 'captcha_audio', - 'role': 'button' - }); - }); + $btn.attr({ + 'aria-label': label, + 'title': label, + 'aria-controls': 'captcha_audio', + 'role': 'button' + }); + + // ✅ 同步更新 sr-only 文字(若有) + var $sr = $btn.find('.sr-only'); + if ($sr.length > 0) { + $sr.text(label); + } + }); }); //刪除td的id @@ -732,20 +774,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(''); @@ -865,7 +907,7 @@ var isLinkImage = $parentA.length > 0 && $parentA.text().replace(/\u00a0/g, '').trim() === ""; // --- 1. 處理「裝飾性圖片」標註 --- - if (currentAlt === "announcement image" || currentAlt === "裝飾圖片" || currentTitle === "裝飾圖片" || currentAlt === "這是一張圖片" || currentTitle === "這是一張圖片") { + if (currentAlt === "announcement image" || currentAlt === "裝飾圖片" || currentTitle === "裝飾圖片" || currentAlt === "這是一張圖片" || currentTitle === "這是一張圖片"||currentAlt === "This is a image" ||currentTitle === "This is a image"){ $img.attr('alt', ''); $img.removeAttr('title'); return; @@ -1067,56 +1109,59 @@ $(function() { } } - // 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); - } + // 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(); + // ✅ 符合 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); - } + // ✅ title 去掉開窗字串後,若與連結文字或圖片原始 alt 相同,則只保留開窗提示 + // ✅ 新增:若 linkText 包含副檔名且 title 也是同樣檔名,也只保留開窗提示 + if ( + (titleWithoutWindow === linkText && linkText !== i18n.link) || + (imgAltOriginal !== '' && titleWithoutWindow === imgAltOriginal) || + (fileExt !== '' && linkText.toLowerCase().endsWith('.' + fileExt) && titleWithoutWindow === linkText) + ) { + $a.attr('title', windowTask); + return; // ✅ 加上 return,避免繼續執行後面的清理邏輯造成二次污染 } + // ✅ 最終清理:若 title 出現空括號 () 則移除並補上正確開窗提示 + var finalTitle = ($a.attr('title') || '').trim(); + if (finalTitle.includes('()')) { + finalTitle = finalTitle.replace(/\(\)/g, '').trim(); + $a.attr('title', finalTitle + ' ' + windowTask); + } + } + // F. 最終清理:移除冗餘 label,避免螢幕閱讀器唸兩次 $a.removeAttr('aria-label'); }); @@ -1150,6 +1195,47 @@ $(function() { fixAccessibilityAll(); }, 800); }); +// 修正漢堡選單按鈕無障礙 +$(function() { + function fixNavbarToggleA11y() { + var isEn = $('html').attr('lang') === 'en'; + var label = isEn ? '開啟或關閉導覽選單' : '開啟或關閉導覽選單'; + + $('.navbar-toggle').each(function() { + var $btn = $(this); + + // 修正 title + $btn.attr('title', label); + + // 修正 sr-only 文字(原本是 "Toggle navigation") + var $sr = $btn.find('.sr-only'); + if ($sr.length) { + $sr.text(label); + } else { + $btn.prepend('' + label + ''); + } + + // 補上 aria-label + $btn.attr('aria-label', label); + + // 補上 aria-expanded(依據目前是否展開) + if (!$btn.attr('aria-expanded')) { + var isExpanded = !$btn.hasClass('collapsed'); + $btn.attr('aria-expanded', isExpanded ? 'true' : 'false'); + } + + // 點擊時同步更新 aria-expanded + $btn.off('click.navA11y').on('click.navA11y', function() { + setTimeout(function() { + var isExpanded = !$('.navbar-toggle').hasClass('collapsed'); + $('.navbar-toggle').attr('aria-expanded', isExpanded ? 'true' : 'false'); + }, 50); + }); + }); + } + + setTimeout(fixNavbarToggleA11y, 500); +}); $(function() { @@ -1502,92 +1588,7 @@ $(function() { resizeTimer = setTimeout(fixAccessKeyM, 150); }); }); - //公告頁籤無障礙 - $(function() { - function fixTabLinearOrder() { - // 只處理內部含有 .tab_nav 的 .w-annc - var $targetAnnc = $('.w-annc').filter(function() { - return $(this).find('.tab_nav').length > 0; - }); - // 若頁面上沒有符合條件的 .w-annc,直接離開 - if ($targetAnnc.length === 0) return; - - var $tabs = $targetAnnc.find('.filter_tab'); - var $anncList = $targetAnnc.find('.w-annc__list'); - - // --- 1. 順向遊走:標籤 -> 對應內容 --- - $tabs.on('keydown', function(e) { - if (e.which === 9 && !e.shiftKey) { - var category = $(this).data('category'); - var $scope = $(this).closest('.w-annc'); // 限定在同一個 .w-annc - var $visibleItems = $scope.find('.w-annc__item[data-category="' + category + '"]:visible'); - - if ($visibleItems.length > 0) { - var $firstLink = $visibleItems.find('a').first(); - if ($firstLink.length > 0) { - e.preventDefault(); - $firstLink.focus(); - } - } - } - if (e.which === 13 || e.which === 32) { - e.preventDefault(); - $(this).click(); - } - }); - - // --- 2. 反向遊走:內容 -> 對應標籤 --- - $anncList.on('keydown', '.w-annc__item a', function(e) { - var $currentLink = $(this); - var $currentItem = $currentLink.closest('.w-annc__item'); - var $scope = $currentLink.closest('.w-annc'); // 限定在同一個 .w-annc - var category = $currentItem.data('category'); - var $visibleItems = $scope.find('.w-annc__item[data-category="' + category + '"]:visible'); - - if (e.which === 9 && e.shiftKey) { - if ($currentLink.is($visibleItems.find('a').first())) { - e.preventDefault(); - $scope.find('.filter_tab[data-category="' + category + '"]').focus(); - } - } - - if (e.which === 9 && !e.shiftKey) { - if ($currentLink.is($visibleItems.find('a').last())) { - var $currentTab = $scope.find('.filter_tab[data-category="' + category + '"]'); - var $nextTab = $currentTab.next('.filter_tab'); - if ($nextTab.length > 0) { - e.preventDefault(); - $nextTab.focus(); - $nextTab.click(); - } - } - } - }); - - // --- 3. 反向遊走:標籤 -> 上一個標籤的內容最後一個連結 --- - $tabs.on('keydown', function(e) { - if (e.which === 9 && e.shiftKey) { - var $scope = $(this).closest('.w-annc'); // 限定在同一個 .w-annc - var $prevTab = $(this).prev('.filter_tab'); - if ($prevTab.length > 0) { - var prevCategory = $prevTab.data('category'); - $prevTab.click(); - - var $prevItems = $scope.find('.w-annc__item[data-category="' + prevCategory + '"]:visible'); - var $lastLink = $prevItems.find('a').last(); - - if ($lastLink.length > 0) { - e.preventDefault(); - $lastLink.focus(); - } - } - } - }); - } - - fixTabLinearOrder(); - }); //導覽選單子選單無障礙狀態修正 (支援多層級) function fixNavMenuA11y() { const $navItems = $('#main-nav li'); @@ -1653,62 +1654,222 @@ $(function() { // 延遲執行,確保動態產生的選單也能被補強 setTimeout(fixEmptyHref, 500); }); - //頁籤無障礙 + //公告頁籤無障礙 $(function() { - /** - * 頁籤導覽 (Tab Navigation) 無障礙補強 - * 1. 容器加入 role="tablist" - * 2. 項目加入 role="tab" - * 3. 動態切換 aria-selected="true/false" - * 4. 確保 Enter 鍵可以觸發切換 (針對 tabindex="0" 的優化) - */ - function fixTabAccessibility() { - var $tabNav = $('.tab_nav'); - var $tabs = $tabNav.find('.filter_tab'); - - // --- 1. 初始化結構語意 --- - $tabNav.attr('role', 'tablist'); - - $tabs.each(function() { - var $this = $(this); - var isActive = $this.hasClass('active'); - - // 加入頁籤角色與選取狀態 - $this.attr({ - 'role': 'tab', - 'aria-selected': isActive ? 'true' : 'false' - }); - - // 修正 Title:讓使用者知道這是切換頁籤 - var tabName = $this.text().trim(); - $this.attr('title', '切換至 ' + tabName); + function fixTabLinearOrder() { + var $targetAnnc = $('.w-annc').filter(function() { + return $(this).find('.tab_nav').length > 0; }); - // --- 2. 監聽切換事件 (點擊或鍵盤) --- - // 假設原本已有切換邏輯,我們在此「補強」屬性的變更 - $tabs.on('click', function() { - var $clickedTab = $(this); + if ($targetAnnc.length === 0) return; - // 先將所有頁籤設為未選取 - $tabs.attr('aria-selected', 'false'); + var $tabs = $targetAnnc.find('.filter_tab'); + var $anncList = $targetAnnc.find('.w-annc__list'); - // 將當前點擊的頁籤設為已選取 - $clickedTab.attr('aria-selected', 'true'); - }); + // 智慧判斷:偵測 filter_tab 用哪個屬性來分類 + // 優先用 data-tags(若有值),否則用 data-category + function getTabKey($tab) { + var tags = $tab.data('tags'); + if (tags && tags !== '') return { attr: 'data-tags', value: tags }; + var category = $tab.data('category'); + if (category && category !== '') return { attr: 'data-category', value: category }; + return null; + } + + // 根據 key 找對應的可見 w-annc__item + function getVisibleItems($scope, key) { + if (!key) return $(); + return $scope.find('.w-annc__item[' + key.attr + '="' + key.value + '"]:visible'); + } + + // 根據 w-annc__item 反查對應的 filter_tab + function getTabFromItem($item, $scope) { + var tags = $item.data('tags'); + if (tags && tags !== '') { + var $tab = $scope.find('.filter_tab[data-tags="' + tags + '"]'); + if ($tab.length) return $tab; + } + var category = $item.data('category'); + if (category && category !== '') { + var $tab = $scope.find('.filter_tab[data-category="' + category + '"]'); + if ($tab.length) return $tab; + } + return $(); + } - // --- 3. 鍵盤操作補強 (針對 tabindex="0" 的非按鈕元素) --- $tabs.on('keydown', function(e) { - // 當按下 Enter (13) 或 Space (32) 時觸發點擊 + var $scope = $(this).closest('.w-annc'); + var key = getTabKey($(this)); + + // 順向 Tab:頁籤 -> 對應內容第一個連結 + if (e.which === 9 && !e.shiftKey) { + var $visibleItems = getVisibleItems($scope, key); + if ($visibleItems.length > 0) { + var $firstLink = $visibleItems.find('a').first(); + if ($firstLink.length > 0) { + e.preventDefault(); + $firstLink.focus(); + } + } + } + + // 反向 Shift+Tab:頁籤 -> 上一個頁籤的內容最後一個連結 + if (e.which === 9 && e.shiftKey) { + var $prevTab = $(this).prev('.filter_tab'); + if ($prevTab.length > 0) { + var prevKey = getTabKey($prevTab); + $prevTab.click(); + + var $prevItems = getVisibleItems($scope, prevKey); + var $lastLink = $prevItems.find('a').last(); + + if ($lastLink.length > 0) { + e.preventDefault(); + $lastLink.focus(); + } + } + } + + // Enter / Space:切換頁籤並移焦點到內容第一個連結 if (e.which === 13 || e.which === 32) { e.preventDefault(); - $(this).trigger('click'); + $(this).click(); + + var $visibleItems = getVisibleItems($scope, key); + var $firstLink = $visibleItems.find('a').first(); + if ($firstLink.length > 0) { + setTimeout(function() { $firstLink.focus(); }, 50); + } + } + }); + + // 反向遊走:內容 -> 對應標籤;Tab 到最後一個連結跳下一個頁籤 + $anncList.on('keydown', '.w-annc__item a', function(e) { + var $currentLink = $(this); + var $currentItem = $currentLink.closest('.w-annc__item'); + var $scope = $currentLink.closest('.w-annc'); + + // 找出當前 item 對應的 filter_tab + var $currentTab = getTabFromItem($currentItem, $scope); + if (!$currentTab.length) return; + + // 找出同類別的所有可見 item + var key = getTabKey($currentTab); + var $visibleItems = getVisibleItems($scope, key); + + // Shift+Tab:若是第一個連結,跳回對應頁籤 + if (e.which === 9 && e.shiftKey) { + if ($currentLink.is($visibleItems.find('a').first())) { + e.preventDefault(); + $currentTab.focus(); + } + } + + // Tab:若是最後一個連結,跳到下一個頁籤並切換 + if (e.which === 9 && !e.shiftKey) { + if ($currentLink.is($visibleItems.find('a').last())) { + var $nextTab = $currentTab.next('.filter_tab'); + if ($nextTab.length > 0) { + e.preventDefault(); + $nextTab.focus(); + $nextTab.click(); + } + } } }); } - // 延遲執行確保頁籤元件已渲染 + setTimeout(fixTabLinearOrder, 500); + }); + + //頁籤無障礙 + $(function () { + function fixTabAccessibility() { + + // 各自獨立處理每組 .tab_nav,避免多組時跨區塊操作問題 + $('.tab_nav').each(function() { + var $tabNav = $(this); + var $tabs = $tabNav.find('li'); + + // --- 1. 初始化結構語意 --- + $tabNav.attr('role', 'tablist'); + + $tabs.each(function () { + var $this = $(this); + var isActive = $this.hasClass('active'); + + $this.attr({ + 'role': 'tab', + 'aria-selected': isActive ? 'true' : 'false', + 'tabindex': isActive ? '0' : '-1' + }); + + var tabName = $this.text().trim(); + $this.attr('title', '切換至 ' + tabName); + }); + + // --- 2. 點擊事件:更新 aria-selected 與 tabindex --- + $tabs.on('click', function () { + var $clickedTab = $(this); + + $tabs.attr('aria-selected', 'false').attr('tabindex', '-1'); + $clickedTab.attr('aria-selected', 'true').attr('tabindex', '0'); + }); + + // --- 3. 鍵盤操作補強 --- + $tabs.on('keydown', function (e) { + var $current = $(this); + var currentIndex = $tabs.index($current); + var lastIndex = $tabs.length - 1; + var $target = null; + + switch (e.which) { + case 13: // Enter + case 32: // Space + e.preventDefault(); + $current.trigger('click'); + break; + + case 37: // ← 左方向鍵:移到前一個頁籤 + case 38: // ↑ 上方向鍵 + e.preventDefault(); + $target = currentIndex > 0 + ? $tabs.eq(currentIndex - 1) + : $tabs.eq(lastIndex); + break; + + case 39: // → 右方向鍵:移到下一個頁籤 + case 40: // ↓ 下方向鍵 + e.preventDefault(); + $target = currentIndex < lastIndex + ? $tabs.eq(currentIndex + 1) + : $tabs.eq(0); + break; + + case 36: // Home:跳到第一個頁籤 + e.preventDefault(); + $target = $tabs.eq(0); + break; + + case 35: // End:跳到最後一個頁籤 + e.preventDefault(); + $target = $tabs.eq(lastIndex); + break; + } + + // 移動焦點並觸發點擊切換 + if ($target && $target.length) { + $tabs.attr('tabindex', '-1'); + $target.attr('tabindex', '0').focus().trigger('click'); + } + }); + }); + } + setTimeout(fixTabAccessibility, 500); }); + + //移除 accesskey="W" 之後的 | 符號 $(function() { function removeSeparatorAfterAccesskeyW() { @@ -1964,29 +2125,31 @@ $(document).ready(function () { }); -$(document).ready(function () { - $('.rucaptcha-image').removeAttr('onload'); - - // 檢查是否已插入過 - if (!$('#captcha_audio').length) { - const audioButton = $(` - - `); - - const audio = $(''); - - $('.rucaptcha-image').after(audioButton, audio); - } -}); + //rucaptcha-image + $(document).ready(function () { + // >>> 修正:先確認頁面上真的有驗證碼圖片,再往下執行,避免沒有驗證碼的頁面也發出多餘的 wav 請求 + if ($('.rucaptcha-image').length) { + $('.rucaptcha-image').removeAttr('onload'); + // 檢查是否已插入過 + if (!$('#captcha_audio').length) { + const audioButton = $(` + + `); + const audio = $(''); + $('.rucaptcha-image').after(audioButton, audio); + } + } + // <<< 修正結束 + }); //萬用表格searchbtn2 $(document).ready(function () { @@ -2988,6 +3151,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') { @@ -3126,11 +3292,87 @@ $(document).ready(function () { setTimeout(function() { $('.internal-page .ad-banner-widget-0 .w-ad-banner__image').attr('alt', ''); }, 800); - // 執行 member等高計算,目前改用flexbox故mark掉 by ika 20160105 - // $(window).load(function() { - // if ($('.index-member-3').length && $(window).width() > 992) { - // ORBITFRONT.member.equalHeight('.i-member-item-inner'); - // } - // }); +setTimeout(function() { + $('.internal-page [data-pp="300"] .w-ba-banner__image').attr('alt', ''); +}, 500); + + //banner英文 + $(function() { + function fixBannerA11yByLang() { + setTimeout(function() { + var pageLang = ($('html').attr('lang') || 'zh-Hant').toLowerCase(); + var isEn = pageLang.startsWith('en'); + + var i18n = { + playControls: isEn ? 'Playback Controls' : '播放控制選項', + resume: isEn ? 'Play' : '繼續播放', + pause: isEn ? 'Pause' : '暫停播放', + prev: isEn ? 'Previous' : '上一張', + next: isEn ? 'Next' : '下一張', + slide: isEn ? 'Slide' : '第', + slideUnit: isEn ? '' : ' 張投影片' + }; + + $('.w-ba-banner').each(function() { + var $banner = $(this); + + // ✅ 播放控制選項 radiogroup label + $banner.find('.controlplay').attr('aria-label', i18n.playControls); + + // ✅ 繼續播放按鈕 + $banner.find('.resume-slide').attr({ + 'aria-label': i18n.resume, + 'title': i18n.resume + }); + $banner.find('.resume-slide p').text(i18n.resume); + + // ✅ 暫停播放按鈕 + $banner.find('.pause-slide').attr({ + 'aria-label': i18n.pause, + 'title': i18n.pause + }); + $banner.find('.pause-slide p').text(i18n.pause); + + // ✅ 上一張按鈕 + $banner.find('.prev-button').attr('aria-label', i18n.prev); + + // ✅ 下一張按鈕 + $banner.find('.next-button').attr('aria-label', i18n.next); + + // ✅ Pager 按鈕 + var $slides = $banner.find('.w-ba-banner__slide'); + $banner.find('.banner-pager button').each(function(index) { + var slideTitle = $slides.eq(index).data('cycle-title') || ''; + var ariaLabel = isEn + ? i18n.slide + ' ' + (index + 1) + (slideTitle ? ' ' + slideTitle : '') + : i18n.slide + (index + 1) + i18n.slideUnit + (slideTitle ? ' ' + slideTitle : ''); + $(this).attr({ + 'aria-label': ariaLabel, + 'title': ariaLabel + }); + }); + }); + + // ✅ Cycle2 初始化後也重新處理 Pager(因為 pager 是動態產生的) + $('.w-ba-banner .cycle-slideshow').on('cycle-post-initialize cycle-after', function() { + var $banner = $(this).closest('.w-ba-banner'); + var $slides = $banner.find('.w-ba-banner__slide'); + $banner.find('.banner-pager button').each(function(index) { + var slideTitle = $slides.eq(index).data('cycle-title') || ''; + var ariaLabel = isEn + ? i18n.slide + ' ' + (index + 1) + (slideTitle ? ' ' + slideTitle : '') + : i18n.slide + (index + 1) + i18n.slideUnit + (slideTitle ? ' ' + slideTitle : ''); + $(this).attr({ + 'aria-label': ariaLabel, + 'title': ariaLabel + }); + }); + }); + + }, 800); + } + + fixBannerA11yByLang(); + }); }(jQuery, window)); diff --git a/assets/stylesheets/template/base/_global.scss b/assets/stylesheets/template/base/_global.scss index ef4aab2..29b93f6 100644 --- a/assets/stylesheets/template/base/_global.scss +++ b/assets/stylesheets/template/base/_global.scss @@ -4,7 +4,12 @@ @import "variables"; .fa-classic, .fa-regular, .fa-solid, .far, .fas ,.fa{ - font-family: var(--fa-style-family, "FontAwesome"); + font-family: "FontAwesome"; +} +li#language-li { + @media(max-width:767px){ + display: none !important; + } } #orbit-bar .orbit-bar-inner > label:focus, #orbit-bar .orbit-bar-inner > label.focus{ .orbit-bar-search-sign-language{ @@ -26,16 +31,16 @@ } } } -label[for="open-orbit-login"] { - @media(max-width:768px){ - display: none!important; - } -} -[accesskey="U"],[accesskey="W"]{ - @media(max-width:768px){ - color: #666!important; - } -} +// label[for="open-orbit-login"] { +// @media(max-width:768px){ +// display: none!important; +// } +// } +// [accesskey="U"],[accesskey="W"]{ +// @media(max-width:768px){ +// color: #666!important; +// } +// } .orbit-bar-inner{ [accesskey="U"]{ height: 40px; @@ -208,6 +213,6 @@ img{ // overflow-x: auto; // } // } -*[data-pp]>.editmode-ps>a, .admin-subpart-area .content>.editmode-ps>a{ - position: !important; -} \ No newline at end of file +input[type=checkbox]:focus { + outline: 0.3125em auto -webkit-focus-ring-color; +} diff --git a/assets/stylesheets/template/layout/content.scss b/assets/stylesheets/template/layout/content.scss index 97decb4..028a705 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; @@ -311,7 +316,7 @@ position: relative; padding: 25px 20px; border: 8px solid #fff; .title02{ - color: #008c82; + color: #05615b; line-height: 100%; font-weight: 500; letter-spacing: 3px; @@ -322,7 +327,7 @@ position: relative; padding: 8px 20px; border-radius: 4px; color: #fff; - background: #008c82; + background: #05615b; &:hover{ background: #06beb2; } diff --git a/assets/stylesheets/template/modules/ad_banner.scss b/assets/stylesheets/template/modules/ad_banner.scss index 61df096..a03ecff 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 ccfd83c..39d0e62 100644 --- a/assets/stylesheets/template/modules/announcement.scss +++ b/assets/stylesheets/template/modules/announcement.scss @@ -2677,12 +2677,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 { @@ -2690,6 +2684,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; text-decoration: underline; diff --git a/assets/stylesheets/template/modules/archives.scss b/assets/stylesheets/template/modules/archives.scss index bc3004d..cf017a5 100644 --- a/assets/stylesheets/template/modules/archives.scss +++ b/assets/stylesheets/template/modules/archives.scss @@ -145,7 +145,7 @@ @extend .unity-title; } .link { background-color: #1368d4 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ -.txt { background-color: #3a8a40 !important; margin-left: 0.5em; } /* 對比 4.6:1 */ +.txt { background-color: #2a7e31 !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 */ @@ -154,7 +154,7 @@ .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 */ +.xls { background-color: #2a7e31 !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/modules/ad_banner/_ad_banner_widget2.html.erb b/modules/ad_banner/_ad_banner_widget2.html.erb index e7c9f79..585915e 100644 --- a/modules/ad_banner/_ad_banner_widget2.html.erb +++ b/modules/ad_banner/_ad_banner_widget2.html.erb @@ -77,3 +77,23 @@ }); }); + \ No newline at end of file diff --git a/modules/announcement/annc_index18.html.erb b/modules/announcement/annc_index18.html.erb index 778bb74..6ecfb02 100644 --- a/modules/announcement/annc_index18.html.erb +++ b/modules/announcement/annc_index18.html.erb @@ -3,7 +3,7 @@