@@ -11,6 +11,70 @@ import { RecordingMode } from "./recordingMode";
1111import axios from "axios" ;
1212import $ from "jquery" ;
1313import { mockReplies } from "../../../utils/bloomApi" ;
14+ import { splitHighlightNames } from "./audioTextHighlightManager" ;
15+
16+ class FakeHighlight {
17+ public ranges : Range [ ] ;
18+
19+ public constructor ( ...ranges : Range [ ] ) {
20+ this . ranges = ranges ;
21+ }
22+ }
23+
24+ type FakeHighlightRegistry = Map < string , FakeHighlight > ;
25+ type TestCssWithHighlights = {
26+ highlights ?: FakeHighlightRegistry ;
27+ } ;
28+
29+ const installCustomHighlightPolyfill = ( targetWindow : Window ) => {
30+ const targetWindowWithCss = targetWindow as Window & {
31+ CSS ?: TestCssWithHighlights ;
32+ } ;
33+ if ( ! targetWindowWithCss . CSS ) {
34+ targetWindowWithCss . CSS = { } ;
35+ }
36+
37+ const cssWithHighlights = targetWindowWithCss . CSS ;
38+ cssWithHighlights . highlights = new Map < string , FakeHighlight > ( ) ;
39+ (
40+ targetWindow as Window & {
41+ Highlight ?: typeof FakeHighlight ;
42+ }
43+ ) . Highlight = FakeHighlight ;
44+ } ;
45+
46+ const getPageWindow = ( ) : Window | undefined => {
47+ const iframe = parent . window . document . getElementById (
48+ "page" ,
49+ ) as HTMLIFrameElement | null ;
50+ return iframe ?. contentWindow ?? undefined ;
51+ } ;
52+
53+ const getCustomHighlightsRegistry = ( ) : FakeHighlightRegistry => {
54+ const targetWindow = getPageWindow ( ) ?? globalThis . window ;
55+ const cssWithHighlights = (
56+ targetWindow as Window & {
57+ CSS ?: TestCssWithHighlights ;
58+ }
59+ ) . CSS ;
60+ if ( ! cssWithHighlights ?. highlights ) {
61+ throw new Error (
62+ "Expected CSS.highlights test polyfill to be installed" ,
63+ ) ;
64+ }
65+
66+ return cssWithHighlights . highlights ;
67+ } ;
68+
69+ const getSplitHighlightTexts = ( ) : string [ ] [ ] => {
70+ const registry = getCustomHighlightsRegistry ( ) ;
71+ return splitHighlightNames . map ( ( name ) => {
72+ const highlight = registry . get ( name ) ;
73+ return highlight
74+ ? highlight . ranges . map ( ( range ) => range . toString ( ) )
75+ : [ ] ;
76+ } ) ;
77+ } ;
1478
1579// Notes:
1680// For any async tests:
@@ -30,13 +94,21 @@ import { mockReplies } from "../../../utils/bloomApi";
3094
3195describe ( "audio recording tests" , ( ) => {
3296 beforeAll ( async ( ) => {
97+ installCustomHighlightPolyfill ( globalThis . window ) ;
98+
3399 await setupForAudioRecordingTests ( ) ;
100+
101+ const pageWindow = getPageWindow ( ) ;
102+ if ( pageWindow ) {
103+ installCustomHighlightPolyfill ( pageWindow ) ;
104+ }
34105 } ) ;
35106
36107 afterEach ( ( ) => {
37108 // Clean up any pending timers to prevent "parent is not defined" errors
38109 // when tests finish before timers fire
39110 theOneAudioRecorder ?. clearTimeouts ( ) ;
111+ getCustomHighlightsRegistry ( ) . clear ( ) ;
40112 } ) ;
41113
42114 // In an earlier version of our API, checkForAnyRecording was designed to fail (404) if there was no recording.
@@ -2059,6 +2131,63 @@ describe("audio recording tests", () => {
20592131 } ) ;
20602132 } ) ;
20612133 } ) ;
2134+
2135+ describe ( "- custom split highlights" , ( ) => {
2136+ it ( "registers the split highlight color groups for the current text box" , ( ) => {
2137+ SetupIFrameFromHtml (
2138+ '<div id="page1"><div class="bloom-translationGroup"><div id="box1" class="bloom-editable audio-sentence ui-audioCurrent bloom-postAudioSplit" data-audiorecordingmode="TextBox" data-audiorecordingendtimes="1.0 2.0 3.0"><p><span id="span1" class="bloom-highlightSegment">One.</span><span id="span2" class="bloom-highlightSegment">Two.</span><span id="span3" class="bloom-highlightSegment">Three.</span><span id="span4" class="bloom-highlightSegment">Four.</span></p></div></div></div>' ,
2139+ ) ;
2140+
2141+ const recording = new AudioRecording ( ) ;
2142+ recording . markAudioSplit ( ) ;
2143+
2144+ expect ( getSplitHighlightTexts ( ) ) . toEqual ( [
2145+ [ "One." , "Four." ] ,
2146+ [ "Two." ] ,
2147+ [ "Three." ] ,
2148+ ] ) ;
2149+ } ) ;
2150+
2151+ it ( "clears split highlights while playback moves to an individual segment" , async ( ) => {
2152+ SetupIFrameFromHtml (
2153+ '<div id="page1"><div class="bloom-translationGroup"><div id="box1" class="bloom-editable audio-sentence ui-audioCurrent bloom-postAudioSplit" data-audiorecordingmode="TextBox" data-audiorecordingendtimes="1.0 2.0"><p><span id="span1" class="bloom-highlightSegment">One.</span><span id="span2" class="bloom-highlightSegment">Two.</span></p></div></div></div>' ,
2154+ ) ;
2155+
2156+ const recording = new AudioRecording ( ) ;
2157+ recording . markAudioSplit ( ) ;
2158+
2159+ const setHighlightToAsync = (
2160+ recording as unknown as {
2161+ setHighlightToAsync ( args : {
2162+ newElement : Element ;
2163+ shouldScrollToElement : boolean ;
2164+ } ) : Promise < void > ;
2165+ }
2166+ ) . setHighlightToAsync . bind ( recording ) ;
2167+
2168+ await setHighlightToAsync ( {
2169+ newElement : getFrameElementById ( "page" , "span1" ) ! ,
2170+ shouldScrollToElement : false ,
2171+ } ) ;
2172+
2173+ expect ( getSplitHighlightTexts ( ) ) . toEqual ( [ [ ] , [ ] , [ ] ] ) ;
2174+ } ) ;
2175+
2176+ it ( "uses only ui-enableHighlight descendants when a segment disables its own background" , ( ) => {
2177+ SetupIFrameFromHtml (
2178+ '<div id="page1"><div class="bloom-translationGroup"><div id="box1" class="bloom-editable audio-sentence ui-audioCurrent bloom-postAudioSplit" data-audiorecordingmode="TextBox" data-audiorecordingendtimes="1.0 2.0"><p><span id="span1" class="bloom-highlightSegment">One.</span><span id="span2" class="bloom-highlightSegment ui-disableHighlight"><span class="ui-enableHighlight">Two</span> <span class="ui-enableHighlight">Three</span></span></p></div></div></div>' ,
2179+ ) ;
2180+
2181+ const recording = new AudioRecording ( ) ;
2182+ recording . markAudioSplit ( ) ;
2183+
2184+ expect ( getSplitHighlightTexts ( ) ) . toEqual ( [
2185+ [ "One." ] ,
2186+ [ "Two" , "Three" ] ,
2187+ [ ] ,
2188+ ] ) ;
2189+ } ) ;
2190+ } ) ;
20622191} ) ;
20632192
20642193function StripEmptyClasses ( html ) {
0 commit comments