diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js index bff3fcc..d695723 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) { @@ -486,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 @@ -624,7 +661,7 @@ } }); if (document.documentElement.lang === 'zh_tw') { - document.documentElement.lang = 'zh-Hant'; + document.documentElement.lang = 'zh-Hant-TW'; } //tab鍵按下 $(document).on('keydown', function(e) { @@ -870,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; @@ -946,7 +983,7 @@ $(function() { var urlParams = new URLSearchParams(window.location.search); var isEditMode = urlParams.get('editmode') === 'on'; - var pageLang = $('html').attr('lang') || 'zh-Hant'; + var pageLang = $('html').attr('lang') || 'zh-Hant-TW'; var isEn = pageLang.toLowerCase().startsWith('en'); var i18n = { @@ -1158,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() { @@ -1679,17 +1757,32 @@ $(function() { var key = getTabKey($currentTab); var $visibleItems = getVisibleItems($scope, key); - // Shift+Tab:若是第一個連結,跳回對應頁籤 + // 找出當前類別的 .w-annc__more + var $more = $scope.find('.w-annc__more-wrap a, .w-annc__more').filter(':visible').first(); + + // Shift+Tab:若在第一個連結,跳回對應頁籤 if (e.which === 9 && e.shiftKey) { if ($currentLink.is($visibleItems.find('a').first())) { e.preventDefault(); $currentTab.focus(); } + // Shift+Tab:若在 .w-annc__more,跳回最後一個公告連結 + if ($more.length && $currentLink.is($more)) { + e.preventDefault(); + $visibleItems.find('a').last().focus(); + } } - // Tab:若是最後一個連結,跳到下一個頁籤並切換 + // Tab:若在最後一個連結,跳到 .w-annc__more if (e.which === 9 && !e.shiftKey) { if ($currentLink.is($visibleItems.find('a').last())) { + if ($more.length) { + e.preventDefault(); + $more.focus(); + } + } + // Tab:若在 .w-annc__more,才跳到下一個頁籤 + if ($more.length && $currentLink.is($more)) { var $nextTab = $currentTab.next('.filter_tab'); if ($nextTab.length > 0) { e.preventDefault(); @@ -1703,6 +1796,7 @@ $(function() { setTimeout(fixTabLinearOrder, 500); }); + //頁籤無障礙 $(function () { function fixTabAccessibility() { @@ -2991,12 +3085,188 @@ $(document).ready(function () { } }); }); -$(document).ready(function () { - setTimeout(function () { - $('iframe.twitter-share-button, iframe.twitter-tweet-button').each(function () { - $(this).attr('title', '分享至 X 在新視窗開啟'); +//cycle2無障礙 +$(document).ready(function() { + // 取得頁面上所有的 Cycle2 輪播圖 + var $allSlideshows = $('.cycle-slideshow'); + + /** + * 核心無障礙狀態刷新函式 + */ + function refreshCycleA11y($el) { + var $items = $el.find('.w-annc__item, .widget-link__item, [class*="cycle-slide"], .widget-pic'); + + $items.each(function() { + var $slide = $(this); + var isActive = $slide.hasClass('cycle-slide-active'); + + if (isActive) { + // ✅ li 只設 aria-hidden,不加 tabindex + $slide.attr('aria-hidden', 'false'); + $slide.removeAttr('tabindex'); // ← 確保 li 本身沒有 tabindex + $slide.find('a, button, input, [tabindex]').attr('tabindex', '0'); + } else { + // 隱藏中的投影片:徹底隔離 + $slide.attr('aria-hidden', 'true'); + $slide.removeAttr('tabindex'); + $slide.find('a, button, input, [tabindex]').attr('tabindex', '-1'); + } + }); + + // --- 防鎖死邊界處理 (Shift + Tab) --- + var $container = $el.closest('.w-annc, .widget-link_wrapper, .widget-link'); + var $prevBtn = $container.find('.btn-left, .prev-button'); + + $el.find('.cycle-slide-active a, .cycle-slide-active button').first() + .off('keydown.a11y').on('keydown.a11y', function(e) { + if (e.keyCode === 9 && e.shiftKey) { + if ($prevBtn.length) { + e.preventDefault(); + $prevBtn.focus(); + } + } + }); + } + + /** + * 針對 widget-link 非語意化標籤 (如 i 標籤當按鈕) 的無障礙補強 + */ + function refreshCycleA11y($el) { + var $items = $el.find('.w-annc__item, .widget-link__item, [class*="cycle-slide"]'); + + $items.each(function() { + var $slide = $(this); + var isActive = $slide.hasClass('cycle-slide-active'); + + if (isActive) { + // ✅ li 只設 aria-hidden,不加 tabindex + $slide.attr('aria-hidden', 'false'); + $slide.removeAttr('tabindex'); // ← 確保 li 本身沒有 tabindex + $slide.find('a, button, input, [tabindex]').attr('tabindex', '0'); + } else { + // 隱藏中的投影片:徹底隔離 + $slide.attr('aria-hidden', 'true'); + $slide.removeAttr('tabindex'); + $slide.find('a, button, input, [tabindex]').attr('tabindex', '-1'); + } + }); + + // --- 防鎖死邊界處理 (Shift + Tab) --- + var $container = $el.closest('.w-annc, .widget-link_wrapper, .widget-link'); + var $prevBtn = $container.find('.btn-left, .prev-button'); + + $el.find('.cycle-slide-active a, .cycle-slide-active button').first() + .off('keydown.a11y').on('keydown.a11y', function(e) { + if (e.keyCode === 9 && e.shiftKey) { + if ($prevBtn.length) { + e.preventDefault(); + $prevBtn.focus(); + } + } + }); + } + + // 輔助函式:切換後更新 A11y 狀態並鎖定焦點 + function triggerPostUpdate($el, $activeBtn) { + $el.one('cycle-after', function() { + setTimeout(function() { + refreshCycleA11y($el); + $activeBtn.focus(); + }, 300); + }); + } + + /** + * 舊有按鈕事件相容與整合 + */ + $(document).on('keydown', '.btn-right, .btn-left', function(e) { + if (e.keyCode === 13) { + var $btn = $(this); + var $el = $btn.closest('.w-annc').find('.cycle-slideshow'); + triggerPostUpdate($el, $btn); + } }); - }, 1500); + + /** + * 綁定 Cycle2 核心事件 + */ + $allSlideshows.on('cycle-initialized cycle-after', function() { + var $this = $(this); + setTimeout(function() { + refreshCycleA11y($this); + }, 300); + }); + + // 初始化執行 + patchWidgetLinkElements(); + + $allSlideshows.each(function() { + var $this = $(this); + setTimeout(function() { + refreshCycleA11y($this); + }, 500); + }); +}); +//post +$(document).ready(function () { + setTimeout(function () { + var pageLang = ($('html').attr('lang') || 'zh-Hant').toLowerCase(); + var isEn = pageLang.startsWith('en'); + var title = isEn ? 'Share to X Open in new window' : '分享至 X 在新視窗開啟'; + + $('iframe.twitter-share-button, iframe.twitter-tweet-button').each(function () { + $(this).attr('title', title); + }); + }, 1500); +}); +$(function() { + function bindIframeFocus() { + var $iframe = $('.twitter-share-button'); + if ($iframe.length === 0) return; + + $iframe.each(function() { + var $wrap = $(this).closest('.tw-share-button'); + + // 讓外層可以被 tab 到並顯示焦點框 + $wrap.attr('tabindex', '-1'); + + $(window).on('blur.twitterFocus', function() { + setTimeout(function() { + 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': '' + }); + }); + }); + } + + // 用 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() { @@ -3187,5 +3457,239 @@ $(document).ready(function () { // ORBITFRONT.member.equalHeight('.i-member-item-inner'); // } // }); +//會員tab邏輯 +$(document).ready(function () { + setTimeout(function () { + $('.dtr-control').removeAttr('tabindex'); + }, 500); +}); +function fixTabKeyboardNav() { + setTimeout(function () { + var $tablist = $('.member-plugins[role="tablist"]'); + var $tabs = $tablist.find('a[role="tab"]'); + // 初始化 roving tabindex 和 aria-selected + $tabs.each(function (i) { + var $tab = $(this); + var isActive = $tab.closest('li').hasClass('active'); + $tab.attr({ + 'tabindex': isActive ? '0' : '-1', + 'aria-selected': isActive ? 'true' : 'false' + }); + }); + + // 方向鍵切換頁籤 + $tabs.on('keydown', function (e) { + var $current = $(this); + var currentIndex = $tabs.index($current); + var $target; + + if (e.keyCode === 39 || e.keyCode === 40) { + // 右鍵或下鍵:下一個 + e.preventDefault(); + $target = $tabs.eq((currentIndex + 1) % $tabs.length); + } else if (e.keyCode === 37 || e.keyCode === 38) { + // 左鍵或上鍵:上一個 + e.preventDefault(); + $target = $tabs.eq((currentIndex - 1 + $tabs.length) % $tabs.length); + } else if (e.keyCode === 36) { + // Home:第一個 + e.preventDefault(); + $target = $tabs.first(); + } else if (e.keyCode === 35) { + // End:最後一個 + e.preventDefault(); + $target = $tabs.last(); + } else { + return; + } + + // 更新 roving tabindex 和 aria-selected + $tabs.attr({ 'tabindex': '-1', 'aria-selected': 'false' }); + $target.attr({ 'tabindex': '0', 'aria-selected': 'true' }); + $target.focus().trigger('click'); + }); + + // 點擊頁籤時同步更新狀態 + $tabs.on('click', function () { + $tabs.attr({ 'tabindex': '-1', 'aria-selected': 'false' }); + $(this).attr({ 'tabindex': '0', 'aria-selected': 'true' }); + }); + + }, 500); +} +$(document).ready(function () { + fixTabKeyboardNav(); +}); +function removeBareUrlLinks() { + setTimeout(function() { + $('.dataTables_wrapper a').each(function() { + var $a = $(this); + var text = $a.text().trim(); + + if (/^https?:\/\//i.test(text)) { + $a.replaceWith(text); + } + }); + }, 500); +} +$(document).ready(function() { + removeBareUrlLinks(); +}); +//麵包屑無障礙 +$(document).ready(function () { + $('.widget-breadcrumb .breadcrumb li:last-child a').attr('aria-current', 'page'); + + // 若尚未有 nav 包住,自動加上 + $('.widget-breadcrumb .breadcrumb').each(function () { + if (!$(this).closest('nav').length) { + $(this).wrap(''); + } + }); +}); +//gallery view +function fixGalleryViewLinkA11y() { + $('a.btn.view').each(function () { + var $a = $(this); + + $a.find('span').each(function () { + var $span = $(this); + + // 避免重複處理 + if ($span.hasClass('sr-only')) return; + + var style = $span.attr('style') || ''; + if (style.indexOf('display: none') !== -1 || style.indexOf('display:none') !== -1) { + $span.removeAttr('style').addClass('sr-only'); + } + }); + + $a.find('i, svg').attr('aria-hidden', 'true'); + }); +} +$(document).ready(function () { + // 比 fixAccessibilityAll 的 800ms 晚,確保最後執行 + setTimeout(fixGalleryViewLinkA11y, 2000); +}); +//No History Records +function fixTicketHistoryStatusA11y() { + var $form = $('#check_history_form'); + if (!$form.length) return; + + // 建立 role=status 播報區(若不存在) + if (!$('#ticket-history-result-status').length) { + $form.after('
'); + } + + var $statusBox = $('#ticket-history-result-status'); + + // MutationObserver 監聽 #history_area 的變化 + var $historyArea = $('#history_area'); + if (!$historyArea.length) return; + + var observer = new MutationObserver(function () { + var $noRecord = $historyArea.find('span.translation_missing'); + if ($noRecord.length) { + // 取得文字(顯示文字或 title 屬性) + var msg = $noRecord.text().trim() || $noRecord.attr('title') || 'No History Records'; + + // 把訊息寫入 role=status 區塊觸發播報 + $statusBox.text('').text(msg); + + // 同時在 span 上加 role=status(雙保險) + if ($noRecord.attr('role') !== 'status') { + $noRecord.attr('role', 'status').attr('aria-live', 'polite').attr('aria-atomic', 'true'); + } + } else { + // 有查到結果時清空播報區 + $statusBox.text(''); + } + }); + + observer.observe($historyArea[0], { + childList: true, + subtree: true + }); +} +$(document).ready(function () { + setTimeout(fixTicketHistoryStatusA11y, 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 05a6e24..8c69c1e 100644 --- a/assets/stylesheets/template/base/_global.scss +++ b/assets/stylesheets/template/base/_global.scss @@ -6,6 +6,11 @@ .fa-classic, .fa-regular, .fa-solid, .far, .fas ,.fa{ 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{ display: block @@ -209,6 +214,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/modules/archives.scss b/assets/stylesheets/template/modules/archives.scss index 4acc096..e39d57c 100644 --- a/assets/stylesheets/template/modules/archives.scss +++ b/assets/stylesheets/template/modules/archives.scss @@ -151,14 +151,18 @@ .i-archive-title { @extend .unity-title; } -.link{margin-right: 0.5em;} -.txt { background-color: #6dbb73; margin-right: 0.5em;} -.xlsx { background-color: #bb6d7f; margin-right: 0.5em;} -.pdf { background-color: #3b8347; margin-right: 0.5em;} -.docx { background-color: #846dbb; margin-right: 0.5em;} -.pptx { background-color: #6d77bb; margin-right: 0.5em;} -.jpg { background-color: #bb6d6d; margin-right: 0.5em;} -.zip { background-color: #dcb957; margin-right: 0.5em;} +.link { background-color: #1368d4 !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 */ +.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: #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 70ef492..585915e 100644 --- a/modules/ad_banner/_ad_banner_widget2.html.erb +++ b/modules/ad_banner/_ad_banner_widget2.html.erb @@ -29,9 +29,7 @@ - +