@@ -49,35 +49,32 @@ function formatUtcRange(startEpochSec, startMs, endMs) {
4949 return fmt ( startDate ) + " - " + fmt ( endDate ) + " (UTC)" ;
5050}
5151
52- /** Format ms from capture start as datetime-local value (local time ). */
53- function msToDatetimeLocal ( captureStartEpochSec , ms ) {
52+ /** Format ms from capture start as UTC string for display (Y-m-d H:i:s ). */
53+ function msToUtcString ( captureStartEpochSec , ms ) {
5454 if ( ! Number . isFinite ( captureStartEpochSec ) || ! Number . isFinite ( ms ) ) return "" ;
5555 const d = new Date ( captureStartEpochSec * 1000 + ms ) ;
5656 const pad2 = ( x ) => String ( x ) . padStart ( 2 , "0" ) ;
57- const pad3 = ( x ) => String ( x ) . padStart ( 3 , "0" ) ;
5857 return (
59- d . getFullYear ( ) +
58+ d . getUTCFullYear ( ) +
6059 "-" +
61- pad2 ( d . getMonth ( ) + 1 ) +
60+ pad2 ( d . getUTCMonth ( ) + 1 ) +
6261 "-" +
63- pad2 ( d . getDate ( ) ) +
64- "T " +
65- pad2 ( d . getHours ( ) ) +
62+ pad2 ( d . getUTCDate ( ) ) +
63+ " " +
64+ pad2 ( d . getUTCHours ( ) ) +
6665 ":" +
67- pad2 ( d . getMinutes ( ) ) +
66+ pad2 ( d . getUTCMinutes ( ) ) +
6867 ":" +
69- pad2 ( d . getSeconds ( ) ) +
70- "." +
71- pad3 ( d . getMilliseconds ( ) )
68+ pad2 ( d . getUTCSeconds ( ) )
7269 ) ;
7370}
7471
75- /** Parse datetime-local value to ms from capture start (UTC epoch sec) . */
76- function datetimeLocalToMs ( captureStartEpochSec , valueStr ) {
77- if ( ! Number . isFinite ( captureStartEpochSec ) || ! valueStr || ! valueStr . trim ( ) ) return NaN ;
78- const d = new Date ( valueStr . trim ( ) ) ;
79- if ( Number . isNaN ( d . getTime ( ) ) ) return NaN ;
80- return d . getTime ( ) - captureStartEpochSec * 1000 ;
72+ /** Parse UTC date string (Y-m-d H:i:s or Y-m-d H:i) to epoch ms . */
73+ function parseUtcStringToEpochMs ( str ) {
74+ if ( ! str || ! str . trim ( ) ) return NaN ;
75+ const s = str . trim ( ) ;
76+ const d = new Date ( s . endsWith ( "Z" ) ? s : s . replace ( " " , "T" ) + "Z" ) ;
77+ return Number . isFinite ( d . getTime ( ) ) ? d . getTime ( ) : NaN ;
8178}
8279
8380class DownloadActionManager {
@@ -411,6 +408,33 @@ class DownloadActionManager {
411408 endDateTimeEntry . disabled = ! hasEpoch ;
412409 }
413410 if ( durationMs <= 0 ) return ;
411+ var fpStart = null , fpEnd = null ;
412+ var epochStart = captureStartEpochSec * 1000 ;
413+ var epochEnd = epochStart + durationMs ;
414+ if ( hasEpoch && typeof flatpickr !== 'undefined' && startDateTimeEntry && endDateTimeEntry ) {
415+ var fpOpts = {
416+ enableTime : true ,
417+ enableSeconds : true ,
418+ utc : true ,
419+ dateFormat : 'Y-m-d H:i:S' ,
420+ time_24hr : true ,
421+ minDate : epochStart ,
422+ maxDate : epochEnd ,
423+ allowInput : true ,
424+ static : true ,
425+ appendTo : webDownloadModal || undefined ,
426+ } ;
427+ flatpickr ( startDateTimeEntry , Object . assign ( { } , fpOpts , {
428+ onChange : function ( ) { syncFromDateTimeEntries ( ) ; }
429+ } ) ) ;
430+ flatpickr ( endDateTimeEntry , Object . assign ( { } , fpOpts , {
431+ onChange : function ( ) { syncFromDateTimeEntries ( ) ; }
432+ } ) ) ;
433+ fpStart = startDateTimeEntry . _flatpickr ;
434+ fpEnd = endDateTimeEntry . _flatpickr ;
435+ startDateTimeEntry . disabled = false ;
436+ endDateTimeEntry . disabled = false ;
437+ }
414438 noUiSlider . create ( sliderEl , {
415439 start : [ 0 , durationMs ] ,
416440 connect : true ,
@@ -444,8 +468,10 @@ class DownloadActionManager {
444468 if ( startTimeEntry ) startTimeEntry . value = String ( Math . round ( startMs ) ) ;
445469 if ( endTimeEntry ) endTimeEntry . value = String ( Math . round ( endMs ) ) ;
446470 if ( hasEpoch ) {
447- if ( startDateTimeEntry ) startDateTimeEntry . value = msToDatetimeLocal ( captureStartEpochSec , startMs ) ;
448- if ( endDateTimeEntry ) endDateTimeEntry . value = msToDatetimeLocal ( captureStartEpochSec , endMs ) ;
471+ if ( fpStart && typeof fpStart . setDate === 'function' ) fpStart . setDate ( epochStart + startMs ) ;
472+ else if ( startDateTimeEntry ) startDateTimeEntry . value = msToUtcString ( captureStartEpochSec , startMs ) ;
473+ if ( fpEnd && typeof fpEnd . setDate === 'function' ) fpEnd . setDate ( epochStart + endMs ) ;
474+ else if ( endDateTimeEntry ) endDateTimeEntry . value = msToUtcString ( captureStartEpochSec , endMs ) ;
449475 }
450476 } ) ;
451477 if ( rangeLabel ) {
@@ -471,10 +497,11 @@ class DownloadActionManager {
471497 if ( startTimeEntry ) startTimeEntry . value = startVal ;
472498 if ( endTimeEntry ) endTimeEntry . value = endVal ;
473499 if ( hasEpoch && startDateTimeEntry && endDateTimeEntry ) {
474- startDateTimeEntry . value = msToDatetimeLocal ( captureStartEpochSec , 0 ) ;
475- endDateTimeEntry . value = msToDatetimeLocal ( captureStartEpochSec , durationMs ) ;
476- startDateTimeEntry . disabled = false ;
477- endDateTimeEntry . disabled = false ;
500+ if ( fpStart && typeof fpStart . setDate === 'function' ) fpStart . setDate ( epochStart ) ;
501+ else startDateTimeEntry . value = msToUtcString ( captureStartEpochSec , 0 ) ;
502+ if ( fpEnd && typeof fpEnd . setDate === 'function' ) fpEnd . setDate ( epochEnd ) ;
503+ else endDateTimeEntry . value = msToUtcString ( captureStartEpochSec , durationMs ) ;
504+ if ( ! fpStart ) { startDateTimeEntry . disabled = false ; endDateTimeEntry . disabled = false ; }
478505 }
479506
480507 function syncSliderFromEntries ( ) {
@@ -492,18 +519,28 @@ class DownloadActionManager {
492519 }
493520 function syncFromDateTimeEntries ( ) {
494521 if ( ! hasEpoch || ! sliderEl . noUiSlider || ! startDateTimeEntry || ! endDateTimeEntry ) return ;
495- var startMs = datetimeLocalToMs ( captureStartEpochSec , startDateTimeEntry . value ) ;
496- var endMs = datetimeLocalToMs ( captureStartEpochSec , endDateTimeEntry . value ) ;
522+ var startMs , endMs ;
523+ if ( startDateTimeEntry . _flatpickr && endDateTimeEntry . _flatpickr ) {
524+ var dStart = startDateTimeEntry . _flatpickr . selectedDates [ 0 ] ;
525+ var dEnd = endDateTimeEntry . _flatpickr . selectedDates [ 0 ] ;
526+ startMs = dStart ? dStart . getTime ( ) - epochStart : 0 ;
527+ endMs = dEnd ? dEnd . getTime ( ) - epochStart : durationMs ;
528+ } else {
529+ startMs = parseUtcStringToEpochMs ( startDateTimeEntry . value ) - epochStart ;
530+ endMs = parseUtcStringToEpochMs ( endDateTimeEntry . value ) - epochStart ;
531+ }
497532 if ( Number . isNaN ( startMs ) || Number . isNaN ( endMs ) ) return ;
498533 startMs = Math . max ( 0 , Math . min ( startMs , durationMs ) ) ;
499534 endMs = Math . max ( 0 , Math . min ( endMs , durationMs ) ) ;
500535 if ( startMs >= endMs ) endMs = Math . min ( startMs + fileCadenceMs , durationMs ) ;
536+ var cur = sliderEl . noUiSlider . get ( ) ;
537+ if ( Math . round ( Number ( cur [ 0 ] ) ) === Math . round ( startMs ) && Math . round ( Number ( cur [ 1 ] ) ) === Math . round ( endMs ) ) return ;
501538 sliderEl . noUiSlider . set ( [ startMs , endMs ] ) ;
502539 }
503540 if ( startTimeEntry ) startTimeEntry . addEventListener ( 'change' , syncSliderFromEntries ) ;
504541 if ( endTimeEntry ) endTimeEntry . addEventListener ( 'change' , syncSliderFromEntries ) ;
505- if ( startDateTimeEntry ) startDateTimeEntry . addEventListener ( 'change' , syncFromDateTimeEntries ) ;
506- if ( endDateTimeEntry ) endDateTimeEntry . addEventListener ( 'change' , syncFromDateTimeEntries ) ;
542+ if ( startDateTimeEntry && ! startDateTimeEntry . _flatpickr ) startDateTimeEntry . addEventListener ( 'change' , syncFromDateTimeEntries ) ;
543+ if ( endDateTimeEntry && ! endDateTimeEntry . _flatpickr ) endDateTimeEntry . addEventListener ( 'change' , syncFromDateTimeEntries ) ;
507544 }
508545
509546 /**
@@ -653,7 +690,6 @@ class DownloadActionManager {
653690 const dataFilesTotalSizeRaw = button . getAttribute ( "data-data-files-total-size" ) ;
654691 const dataFilesTotalSize = dataFilesTotalSizeRaw !== null && dataFilesTotalSizeRaw !== '' ? parseInt ( dataFilesTotalSizeRaw , 10 ) : NaN ;
655692 const captureStartEpochSec = parseInt ( button . getAttribute ( "data-capture-start-epoch-sec" ) , 10 ) ;
656- const captureUuid = button . getAttribute ( "data-capture-uuid" ) || undefined ;
657693 this . initializeCaptureDownloadSlider (
658694 Number . isNaN ( durationMs ) ? 0 : durationMs ,
659695 Number . isNaN ( fileCadenceMs ) ? 1000 : fileCadenceMs ,
@@ -663,7 +699,7 @@ class DownloadActionManager {
663699 dataFilesCount : Number . isNaN ( dataFilesCount ) ? 0 : dataFilesCount ,
664700 totalFilesCount : Number . isNaN ( totalFilesCount ) ? 0 : totalFilesCount ,
665701 dataFilesTotalSize : Number . isNaN ( dataFilesTotalSize ) ? undefined : dataFilesTotalSize ,
666- captureUuid : captureUuid ,
702+ captureUuid : captureUuid || undefined ,
667703 captureStartEpochSec : Number . isNaN ( captureStartEpochSec ) ? undefined : captureStartEpochSec ,
668704 } ,
669705 ) ;
0 commit comments