diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js index 59e477e..3ba7c4b 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來減少名稱衝突的機會 @@ -865,7 +899,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; @@ -1141,87 +1175,132 @@ $(function() { // }); // }); // } - $(function() { - function smartFixIcons() { - var isEn = $('html').attr('lang') === 'en'; +$(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' : '關閉視窗' - }; + 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(); + $('i').each(function() { + var $icon = $(this); + var $parent = $icon.parent(); - // 1. 所有圖示先對螢幕閱讀器隱藏 - $icon.attr('aria-hidden', 'true'); + // 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; + // 特判:.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; + } - // 2. 已有 aria-label 或 sr-only 就不重複處理 - if ($icon.attr('aria-label') || $icon.next('.sr-only').length > 0 || $parent.find('.sr-only').length > 0) { - 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; + } - 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; + // 特判:.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'); } - - // --- 3. 執行補強 --- - if (labelText !== '') { - if ($container.length > 0 && $container.text().trim() === '') { - $container.attr('aria-label', labelText); - } else { - $icon.after('' + labelText + ''); - } + if ($icon.next('.sr-only').length === 0) { + $icon.after('' + labels.toggleDesc + ''); } - }); - } + return; + } - setTimeout(smartFixIcons, 500); - }); + // 特判:.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')=="") @@ -2736,6 +2815,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') { @@ -2787,6 +2869,89 @@ $(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); }); // 執行 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 1bece9e..dc8b9a0 100644 --- a/assets/stylesheets/template/base/_global.scss +++ b/assets/stylesheets/template/base/_global.scss @@ -11,6 +11,9 @@ 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/modules/archives.scss b/assets/stylesheets/template/modules/archives.scss index 466f406..bc3004d 100644 --- a/assets/stylesheets/template/modules/archives.scss +++ b/assets/stylesheets/template/modules/archives.scss @@ -144,18 +144,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/modules/announcement/_annc_widget1.html.erb b/modules/announcement/_annc_widget1.html.erb index 37a44d2..801531d 100644 --- a/modules/announcement/_annc_widget1.html.erb +++ b/modules/announcement/_annc_widget1.html.erb @@ -7,7 +7,7 @@