diff --git a/assets/javascripts/app.js b/assets/javascripts/app.js index f82515c..3278c4b 100644 --- a/assets/javascripts/app.js +++ b/assets/javascripts/app.js @@ -3574,137 +3574,252 @@ $(function() { // } // }); - //banner英文 - $(function() { - function fixBannerA11yByLang() { - setTimeout(function() { - var pageLang = ($('html').attr('lang') || 'zh-Hant').toLowerCase(); - var isEn = pageLang.startsWith('en'); +//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 ? '' : ' 張投影片' - }; + 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); + $('.w-ba-banner').each(function() { + var $banner = $(this); - // ✅ 播放控制選項 radiogroup label - $banner.find('.controlplay').attr('aria-label', i18n.playControls); + $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('.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('.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('.prev-button').attr('aria-label', i18n.prev); + $banner.find('.next-button').attr('aria-label', i18n.next); - // ✅ 下一張按鈕 - $banner.find('.next-button').attr('aria-label', i18n.next); + 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 }); + }); + }); - // ✅ 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 + 切換後播報當前圖片資訊 + $('.w-ba-banner .cycle-slideshow').on('cycle-post-initialize cycle-after', function(event) { + var $slideshow = $(this); + var $banner = $slideshow.closest('.w-ba-banner'); + var $slides = $banner.find('.w-ba-banner__slide'); - // ✅ 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 - }); - }); - }); + // 更新 Pager aria-label + $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); - } + // ✅ 問題1:cycle-after 時用 live region 播報當前圖片資訊 + if (event.type === 'cycle-after') { + var opts = $slideshow.data('cycle.opts'); + if (opts) { + var currentIndex = opts.currSlide; + var $currentSlide = $slides.eq(currentIndex); + var currentTitle = $currentSlide.data('cycle-title') || ''; + var currentAlt = $currentSlide.find('img').attr('alt') || ''; + var announceText = isEn + ? 'Slide ' + (currentIndex + 1) + ' of ' + $slides.length + (currentTitle ? ': ' + currentTitle : (currentAlt ? ': ' + currentAlt : '')) + : '第 ' + (currentIndex + 1) + ' 張,共 ' + $slides.length + ' 張' + (currentTitle ? ':' + currentTitle : (currentAlt ? ':' + currentAlt : '')); + + var $announcer = $banner.find('.banner-announcer'); + if ($announcer.length === 0) { + $announcer = $('
'); + $banner.append($announcer); + } + $announcer.text(''); + setTimeout(function() { + $announcer.text(announceText); + }, 100); + } + } + }); + + }, 800); + } + + fixBannerA11yByLang(); +}); - fixBannerA11yByLang(); - }); //bannercontrolplay $(function() { - function fixBannerPlayPauseA11y() { + function fixBannerPlayPauseA11y() { + setTimeout(function() { + var pageLang = ($('html').attr('lang') || 'zh-Hant').toLowerCase(); + var isEn = pageLang.startsWith('en'); + + var i18n = { + resume: isEn ? 'Play' : '繼續播放', + pause: isEn ? 'Pause' : '暫停播放' + }; + + $('.w-ba-banner').each(function() { + var $banner = $(this); + var $controlplay = $banner.find('.controlplay'); + var $slideshow = $banner.find('.cycle-slideshow'); + + $controlplay.removeAttr('role aria-label'); + + var $resume = $banner.find('.resume-slide'); + $resume + .attr('role', 'button') + .attr('aria-pressed', $resume.hasClass('active') ? 'true' : 'false') + .attr('aria-label', i18n.resume) + .attr('title', i18n.resume) + .removeAttr('aria-checked aria-live'); + + var $pause = $banner.find('.pause-slide'); + $pause + .attr('role', 'button') + .attr('aria-pressed', $pause.hasClass('active') ? 'true' : 'false') + .attr('aria-label', i18n.pause) + .attr('title', i18n.pause) + .removeAttr('aria-checked aria-live'); + + $resume.off('click.bannerA11y').on('click.bannerA11y', function() { + $resume.attr('aria-pressed', 'true'); + $pause.attr('aria-pressed', 'false'); + }); + + $pause.off('click.bannerA11y').on('click.bannerA11y', function() { + $pause.attr('aria-pressed', 'true'); + $resume.attr('aria-pressed', 'false'); + }); + + // ✅ 問題2:focus 時動態讀出當前播放狀態 + $resume.off('focus.bannerStatus').on('focus.bannerStatus', function() { + var isPlaying = !$slideshow.hasClass('cycle-paused'); + var statusText = isEn + ? 'Play button. Current status: ' + (isPlaying ? 'Playing' : 'Paused') + : '繼續播放按鈕。目前狀態:' + (isPlaying ? '播放中' : '已暫停'); + $(this).attr('aria-label', statusText); + }); + $resume.off('blur.bannerStatus').on('blur.bannerStatus', function() { + $(this).attr('aria-label', i18n.resume); + }); + + $pause.off('focus.bannerStatus').on('focus.bannerStatus', function() { + var isPlaying = !$slideshow.hasClass('cycle-paused'); + var statusText = isEn + ? 'Pause button. Current status: ' + (isPlaying ? 'Playing' : 'Paused') + : '暫停播放按鈕。目前狀態:' + (isPlaying ? '播放中' : '已暫停'); + $(this).attr('aria-label', statusText); + }); + $pause.off('blur.bannerStatus').on('blur.bannerStatus', function() { + $(this).attr('aria-label', i18n.pause); + }); + + }); + + }, 800); + } + + fixBannerPlayPauseA11y(); +}); +//banner進入自動暫停 +$(function() { + function fixBannerFocusPauseA11y() { + setTimeout(function() { + $('.w-ba-banner').each(function() { + var $banner = $(this); + var $slideshow = $banner.find('.cycle-slideshow'); + var $pauseBtn = $banner.find('.pause-slide'); + var $resumeBtn = $banner.find('.resume-slide'); + + var manuallyPaused = false; + + // ✅ 焦點進入輪播區域時自動暫停 + $banner.on('focusin', function() { + $slideshow.cycle('pause'); + $pauseBtn.addClass('active').attr('aria-checked', 'true'); + $resumeBtn.removeClass('active').attr('aria-checked', 'false'); + }); + + // ✅ 若使用者手動按下暫停,焦點離開後不自動恢復 + $pauseBtn.on('click', function() { + manuallyPaused = true; + }); + + $resumeBtn.on('click', function() { + manuallyPaused = false; + }); + + // ✅ 覆寫 focusout 加入 manuallyPaused 判斷 + $banner.off('focusout').on('focusout', function() { + setTimeout(function() { + if (!$banner.find(':focus').length && !manuallyPaused) { + $slideshow.cycle('resume'); + $resumeBtn.addClass('active').attr('aria-checked', 'true'); + $pauseBtn.removeClass('active').attr('aria-checked', 'false'); + } + }, 150); + }); + + }); + }, 800); + } + + fixBannerFocusPauseA11y(); +}); +//banner pager 按下狀態 +$(function() { + function fixBannerPagerPressedA11y() { + setTimeout(function() { + function syncPagerPressed($banner) { + $banner.find('.banner-pager button').each(function() { + var $btn = $(this); + $btn.attr('aria-pressed', $btn.hasClass('active-slide') ? 'true' : 'false'); + }); + } + + // 初始狀態(頁面載入當下預設顯示的那張圖) + $('.w-ba-banner').each(function() { + syncPagerPressed($(this)); + }); + + // Cycle2 初始化完成、以及每次切換投影片後,同步 aria-pressed + $('.w-ba-banner .cycle-slideshow').on('cycle-post-initialize cycle-after', function() { + syncPagerPressed($(this).closest('.w-ba-banner')); + }); + + // 直接點擊 pager 按鈕時,class 切換與 cycle-after 觸發之間可能有極短延遲, + // 這裡多補一次同步,確保狀態不會滯後 + $(document).on('click', '.banner-pager button', function() { + var $banner = $(this).closest('.w-ba-banner'); setTimeout(function() { - var pageLang = ($('html').attr('lang') || 'zh-Hant').toLowerCase(); - var isEn = pageLang.startsWith('en'); + syncPagerPressed($banner); + }, 50); + }); + }, 800); + } - var i18n = { - resume: isEn ? 'Play' : '繼續播放', - pause: isEn ? 'Pause' : '暫停播放' - }; - - $('.w-ba-banner').each(function() { - var $banner = $(this); - var $controlplay = $banner.find('.controlplay'); - - // ✅ 把 radiogroup 改為一般容器 - $controlplay.removeAttr('role aria-label'); - - // ✅ 繼續播放按鈕 - var $resume = $banner.find('.resume-slide'); - $resume - .attr('role', 'button') - .attr('aria-pressed', $resume.hasClass('active') ? 'true' : 'false') - .attr('aria-label', i18n.resume) - .attr('title', i18n.resume) - .removeAttr('aria-checked aria-live'); - - // ✅ 暫停播放按鈕 - var $pause = $banner.find('.pause-slide'); - $pause - .attr('role', 'button') - .attr('aria-pressed', $pause.hasClass('active') ? 'true' : 'false') - .attr('aria-label', i18n.pause) - .attr('title', i18n.pause) - .removeAttr('aria-checked aria-live'); - - // ✅ 點擊後同步 aria-pressed - $resume.off('click.bannerA11y').on('click.bannerA11y', function() { - $resume.attr('aria-pressed', 'true'); - $pause.attr('aria-pressed', 'false'); - }); - - $pause.off('click.bannerA11y').on('click.bannerA11y', function() { - $pause.attr('aria-pressed', 'true'); - $resume.attr('aria-pressed', 'false'); - }); - }); - - }, 800); - } - - fixBannerPlayPauseA11y(); + fixBannerPagerPressedA11y(); }); }(jQuery, window)); diff --git a/assets/stylesheets/template/layout/content.scss b/assets/stylesheets/template/layout/content.scss index 8c94ecf..cee18bc 100644 --- a/assets/stylesheets/template/layout/content.scss +++ b/assets/stylesheets/template/layout/content.scss @@ -1,6 +1,9 @@ @charset "utf-8"; @import "../initial"; +.accessibility_mode a:focus{ + outline: 0.3125em auto $theme-color-second !important; +} .line-it-button{ .label{ color: #333!important; diff --git a/modules/ad_banner/_ad_banner_widget1.html.erb b/modules/ad_banner/_ad_banner_widget1.html.erb index 72699e2..5a2097b 100644 --- a/modules/ad_banner/_ad_banner_widget1.html.erb +++ b/modules/ad_banner/_ad_banner_widget1.html.erb @@ -65,7 +65,22 @@ }) $('[data-subpart-id="{{subpart-id}}"] .prev-button').click(function(){ $(this).parent("ul").parent('.w-ba-banner').find(".cycle-slideshow").cycle("prev"); - }) + }); + /* 修正點:處理 Pager 無障礙朗讀文字 */ + $('.cycle-slideshow').on('cycle-post-initialize', function(event, optionHash) { + var $container = $(this).closest('.w-ba-banner'); + var $slides = $(this).find('.w-ba-banner__slide'); + var $pagerButtons = $container.find(".banner-pager button"); + + $pagerButtons.each(function(index) { + var slideTitle = $slides.eq(index).data('cycle-title') || ""; + var ariaLabel = "第 " + (index + 1) + " 張投影片 " + slideTitle; + $(this).attr({ + "aria-label": ariaLabel, + "title": ariaLabel + }); + }); + });