From e23455a0c700f6dde95c00e81eac424c99c57c66 Mon Sep 17 00:00:00 2001 From: Ray Lin Date: Sat, 23 Sep 2017 10:51:47 +0800 Subject: [PATCH] Bug 1396094 - Handle change event of textTracks to update the closed caption UI state. r=jaws MozReview-Commit-ID: KpjXhxUPDKR --HG-- extra : rebase_source : fedd916f37621fa1ccd3d0f0f22402fafc8752d9 --- .../tests/widgets/test_videocontrols_vtt.html | 116 ++++++++---------- toolkit/content/widgets/videocontrols.xml | 23 ++-- 2 files changed, 60 insertions(+), 79 deletions(-) diff --git a/toolkit/content/tests/widgets/test_videocontrols_vtt.html b/toolkit/content/tests/widgets/test_videocontrols_vtt.html index 4728bf0c04f1..dc9a93f5f7ef 100644 --- a/toolkit/content/tests/widgets/test_videocontrols_vtt.html +++ b/toolkit/content/tests/widgets/test_videocontrols_vtt.html @@ -3,6 +3,7 @@ Video controls test - VTT + @@ -23,102 +24,87 @@ const ttList = getAnonElementWithinVideoByAttribute(video, "anonid", "textTrackList"); const testCases = []; - testCases.push(() => new Promise(resolve => { + add_task(async function wait_for_media_ready() { + await new Promise(resolve => window.addEventListener("load", resolve, {once: true})); + await SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}); + await new Promise(resolve => { + video.src = "seek_with_sound.ogg"; + video.addEventListener("loadedmetadata", resolve); + }); + }); + + add_task(async function check_inital_state() { is(ccBtn.getAttribute("hidden"), "true", "CC button should hide"); + }); - resolve(); - })); - - testCases.push(() => new Promise(resolve => { + add_task(async function check_unsupported_type_added() { video.addTextTrack("descriptions", "English", "en"); video.addTextTrack("chapters", "English", "en"); video.addTextTrack("metadata", "English", "en"); - SimpleTest.executeSoon(() => { - is(ccBtn.getAttribute("hidden"), "true", "CC button should hide if no supported tracks provided"); + await new Promise(SimpleTest.executeSoon); + is(ccBtn.getAttribute("hidden"), "true", "CC button should hide if no supported tracks provided"); + }); - resolve(); - }); - })); - - testCases.push(() => new Promise(resolve => { + add_task(async function check_cc_button_present() { const sub = video.addTextTrack("subtitles", "English", "en"); sub.mode = "disabled"; - SimpleTest.executeSoon(() => { - is(ccBtn.hasAttribute("hidden"), false, "CC button should show"); - is(ccBtn.hasAttribute("enabled"), false, "CC button should be disabled"); + await new Promise(SimpleTest.executeSoon); + is(ccBtn.hasAttribute("hidden"), false, "CC button should show"); + is(ccBtn.hasAttribute("enabled"), false, "CC button should be disabled"); + }); - resolve(); - }); - })); - - testCases.push(() => new Promise(resolve => { + add_task(async function check_cc_button_be_enabled() { const subtitle = video.addTextTrack("subtitles", "English", "en"); subtitle.mode = "showing"; - SimpleTest.executeSoon(() => { - is(ccBtn.getAttribute("enabled"), "true", "CC button should be enabled"); - subtitle.mode = "disabled"; + await new Promise(SimpleTest.executeSoon); + is(ccBtn.getAttribute("enabled"), "true", "CC button should be enabled"); + subtitle.mode = "disabled"; + }); - resolve(); - }); - })); - - testCases.push(() => new Promise(resolve => { + add_task(async function check_cpations_type() { const caption = video.addTextTrack("captions", "English", "en"); caption.mode = "showing"; - SimpleTest.executeSoon(() => { - is(ccBtn.getAttribute("enabled"), "true", "CC button should be enabled"); + await new Promise(SimpleTest.executeSoon); + is(ccBtn.getAttribute("enabled"), "true", "CC button should be enabled"); + }); - resolve(); - }); - })); - - testCases.push(() => new Promise(resolve => { + add_task(async function check_track_ui_state() { synthesizeMouseAtCenter(ccBtn, {}); - SimpleTest.executeSoon(() => { - is(ttList.hasAttribute("hidden"), false, "Texttrack menu should show up"); - is(ttList.lastChild.getAttribute("on"), "true", "The last added item should be highlighted"); + await new Promise(SimpleTest.executeSoon); + is(ttList.hasAttribute("hidden"), false, "Texttrack menu should show up"); + is(ttList.lastChild.getAttribute("on"), "true", "The last added item should be highlighted"); + }); - resolve(); - }); - })); - - testCases.push(() => new Promise(resolve => { + add_task(async function check_select_texttrack() { const tt = ttList.children[1]; isnot(tt.getAttribute("on"), "true", "Item should be off before click"); synthesizeMouseAtCenter(tt, {}); - SimpleTest.executeSoon(() => { - is(tt.getAttribute("on"), "true", "Selected item should be enabled"); - is(ttList.getAttribute("hidden"), "true", "Should hide texttrack menu once clicked on an item"); + await new Promise(SimpleTest.executeSoon); + is(tt.getAttribute("on"), "true", "Selected item should be enabled"); + is(ttList.getAttribute("hidden"), "true", "Should hide texttrack menu once clicked on an item"); + }); - resolve(); - }); - })); + add_task(async function check_change_texttrack_mode() { + const tts = [...video.textTracks]; - function executeTestCases(tasks) { - return tasks.reduce((promise, task) => promise.then(task), Promise.resolve()); - } + tts.forEach(tt => tt.mode = "hidden"); + await new Promise(SimpleTest.executeSoon); + is(ccBtn.hasAttribute("enabled"), false, "CC button should be disabled"); - function loadedmetadata() { - executeTestCases(testCases).then(SimpleTest.finish); - } + // enable the last text track. + tts[tts.length - 1].mode = "showing"; + await new Promise(SimpleTest.executeSoon); + is(ccBtn.hasAttribute("enabled"), true, "CC button should be enabled"); + is(ttList.lastChild.getAttribute("on"), "true", "The last item should be highlighted"); + }); - function startMediaLoad() { - video.src = "seek_with_sound.ogg"; - video.addEventListener("loadedmetadata", loadedmetadata); - } - - function loadevent() { - SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, startMediaLoad); - } - - window.addEventListener("load", loadevent); diff --git a/toolkit/content/widgets/videocontrols.xml b/toolkit/content/widgets/videocontrols.xml index 8a82146f47d9..2ec5534ff6da 100644 --- a/toolkit/content/widgets/videocontrols.xml +++ b/toolkit/content/widgets/videocontrols.xml @@ -213,7 +213,6 @@ controlsOverlay: null, fullscreenButton: null, layoutControls: null, - currentTextTrackIndex: 0, textTracksCount: 0, randomID: 0, @@ -1476,6 +1475,13 @@ return Array.prototype.filter.call(this.video.textTracks, this.isSupportedTextTrack); }, + get currentTextTrackIndex() { + const showingTT = this.overlayableTextTracks.find(tt => tt.mode == "showing"); + + // fallback to off button if there's no showing track. + return showingTT ? showingTT.index : 0; + }, + isClosedCaptionOn() { for (let tt of this.overlayableTextTracks) { if (tt.mode === "showing") { @@ -1551,20 +1557,12 @@ for (let tt of this.overlayableTextTracks) { if (tt.index === index) { tt.mode = "showing"; - - this.currentTextTrackIndex = tt.index; } else { tt.mode = "disabled"; } } - // should fallback to off - if (this.currentTextTrackIndex !== index) { - this.currentTextTrackIndex = 0; - } - this.textTrackList.setAttribute("hidden", "true"); - this.setClosedCaptionButtonState(); }, onControlBarTransitioned() { @@ -1602,11 +1600,7 @@ this.textTracksCount--; } - if (idx === this.currentTextTrackIndex) { - this.currentTextTrackIndex = 0; - - this.video.dispatchEvent(new CustomEvent("texttrackchange")); - } + this.video.dispatchEvent(new CustomEvent("texttrackchange")); } this.setClosedCaptionButtonState(); @@ -1850,6 +1844,7 @@ addListener(this.volumeControl, "input", this.updateVolume); addListener(this.video.textTracks, "addtrack", this.onTextTrackAdd); addListener(this.video.textTracks, "removetrack", this.onTextTrackRemove); + addListener(this.video.textTracks, "change", this.setClosedCaptionButtonState); } this.log("--- videocontrols initialized ---");