@@ -67,6 +67,26 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
6767 "X-CSRFToken" : getCookie ( "csrftoken" ) ,
6868 } ;
6969
70+ $scope . scrollToElement = function ( id ) {
71+ setTimeout ( function ( ) {
72+ const el = document . getElementById ( id ) ;
73+ if ( el ) {
74+ const rect = el . getBoundingClientRect ( ) ;
75+ const isVisible =
76+ rect . top >= 0 &&
77+ rect . bottom <=
78+ ( window . innerHeight || document . documentElement . clientHeight ) ;
79+
80+ if ( ! isVisible ) {
81+ const topOffset = rect . top + window . scrollY - 60 ; // adjust for sticky header
82+ window . scrollTo ( { top : topOffset , behavior : "smooth" } ) ;
83+ }
84+ } else {
85+ console . warn ( "Element not found:" , id ) ;
86+ }
87+ } , 100 ) ;
88+ } ;
89+
7090 $scope . seekTo = function ( timecode ) {
7191 const player = window . top . player ;
7292 if ( player ) {
@@ -92,27 +112,18 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
92112 }
93113 } ;
94114
115+ $scope . jumpToChapter = function ( timecode ) {
116+ $scope . scrollToElement ( "videoPlayerSection" ) ;
117+ $scope . seekTo ( timecode ) ;
118+ } ;
119+
95120 $scope . toggleInThisVideo = function ( tab ) {
96121 $scope . showInThisVideoSection = ! $scope . showInThisVideoSection ;
97122 $scope . activeTab = tab ;
98123
99124 // Jump to Transcriptions section
100125 if ( $scope . showInThisVideoSection ) {
101- setTimeout ( function ( ) {
102- const el = document . getElementById ( "transcriptionsSection" ) ;
103- if ( el ) {
104- const rect = el . getBoundingClientRect ( ) ;
105- const isVisible =
106- rect . top >= 0 &&
107- rect . bottom <=
108- ( window . innerHeight || document . documentElement . clientHeight ) ;
109-
110- if ( ! isVisible ) {
111- const topOffset = rect . top + window . scrollY - 60 ;
112- window . scrollTo ( { top : topOffset , behavior : "smooth" } ) ;
113- }
114- }
115- } , 100 ) ;
126+ $scope . scrollToElement ( "inThisVideoSection" ) ;
116127 }
117128 } ;
118129
@@ -197,8 +208,6 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
197208 // Use chapters from API or parse from description as fallback
198209 if ( record . metadata . chapters && record . metadata . chapters . length > 0 ) {
199210 $scope . chapters = record . metadata . chapters ;
200- } else if ( record . metadata . description ) {
201- $scope . chapters = $scope . parseChapters ( record . metadata . description ) ;
202211 }
203212
204213 // Set default active tab based on what's available (prioritize chapters)
@@ -345,50 +354,6 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
345354 return `${ minutes } :${ paddedSecs } ` ;
346355 } ;
347356
348- $scope . parseChapters = function ( description ) {
349- if ( ! description ) return [ ] ;
350-
351- // Regex pattern to match timestamp formats: 0:00, 00:00, 0:00:00, 00:00:00
352- const pattern =
353- / (?: ^ | \n ) \s * ( \d { 1 , 2 } : (?: \d { 1 , 2 } : ) ? \d { 1 , 2 } ) \s * [ - \s ] * ( .+ ?) (? = \n | $ ) / gm;
354- const chapters = [ ] ;
355- let match ;
356-
357- while ( ( match = pattern . exec ( description ) ) !== null ) {
358- const [ , timestampStr , title ] = match ;
359-
360- // Parse timestamp to seconds
361- const timeParts = timestampStr . split ( ":" ) ;
362- let totalSeconds ;
363-
364- if ( timeParts . length === 2 ) {
365- // MM:SS format
366- const [ minutes , seconds ] = timeParts . map ( Number ) ;
367- totalSeconds = minutes * 60 + seconds ;
368- } else if ( timeParts . length === 3 ) {
369- // HH:MM:SS format
370- const [ hours , minutes , seconds ] = timeParts . map ( Number ) ;
371- totalSeconds = hours * 3600 + minutes * 60 + seconds ;
372- } else {
373- continue ;
374- }
375-
376- // Clean up title
377- const cleanTitle = title . trim ( ) ;
378- if ( cleanTitle ) {
379- chapters . push ( {
380- timestamp : timestampStr ,
381- seconds : totalSeconds ,
382- title : cleanTitle ,
383- } ) ;
384- }
385- }
386-
387- // Sort chapters by timestamp
388- chapters . sort ( ( a , b ) => a . seconds - b . seconds ) ;
389- return chapters ;
390- } ;
391-
392357 $scope . setActiveTab = function ( tab ) {
393358 $scope . activeTab = tab ;
394359 } ;
@@ -415,7 +380,7 @@ function cdsRecordController($scope, $sce, $http, $timeout, $filter) {
415380 }
416381
417382 // Return clickable timestamp using onclick for ng-bind-html compatibility
418- return `<a href="javascript:void(0)" class="timestamp-link" onclick="(function(){ try { angular.element(document.querySelector('.cds-detail-description')).scope().seekTo (${ totalSeconds } ); } catch(e) { console.error('Could not seek to timestamp:', e); } })()" style="color: #2196F3; font-weight: 600; cursor: pointer;">${ match } </a>` ;
383+ return `<a href="javascript:void(0)" class="timestamp-link" onclick="(function(){ try { angular.element(document.querySelector('.cds-detail-description')).scope().jumpToChapter (${ totalSeconds } ); } catch(e) { console.error('Could not seek to timestamp:', e); } })()" style="color: #2196F3; font-weight: 600; cursor: pointer;">${ match } </a>` ;
419384 } ) ;
420385 } ;
421386
0 commit comments