11/*! (C) The Hyperaudio Project. MIT @license: en.wikipedia.org/wiki/MIT_License. */
2- /*! Version 2.2.0 */
2+ /*! Version 2.2.3 */
33
44'use strict' ;
55
@@ -420,7 +420,8 @@ class HyperaudioLite {
420420 //TODO convert to binary search for below for quicker startup
421421 if ( this . start && this . end ) {
422422 for ( let i = 1 ; i < words . length ; i ++ ) {
423- const wordStart = Math . round ( words [ i ] . getAttribute ( 'data-m' ) / 100 ) / 10 ;
423+ let startTime = parseInt ( words [ i ] . getAttribute ( 'data-m' ) ) / 1000 ;
424+ let wordStart = ( Math . round ( startTime * 100 ) / 100 ) . toFixed ( 2 ) ;
424425 if ( wordStart >= parseFloat ( this . start ) && parseFloat ( this . end ) > wordStart ) {
425426 words [ i ] . classList . add ( 'share-match' ) ;
426427 }
@@ -451,100 +452,67 @@ class HyperaudioLite {
451452 return wordArr ;
452453 } ;
453454
454- getSelectionMediaFragment = ( ) => {
455- let fragment = null ;
456- let selection = null ;
457-
458- if ( window . getSelection ) {
459- selection = window . getSelection ( ) ;
460- } else if ( document . selection ) {
461- selection = document . selection . createRange ( ) ;
462- }
455+ getSelectionRange = ( ) => {
456+ const selection = window . getSelection ( ) ;
457+ if ( selection . rangeCount === 0 ) return null ;
463458
464- // check to see if selection is actually inside the transcript
465- let insideTranscript = false ;
466- let parentElement = selection . focusNode ;
467- while ( parentElement !== null ) {
468- if ( parentElement . id === this . transcript . id ) {
469- insideTranscript = true ;
470- break ;
459+ const range = selection . getRangeAt ( 0 ) ;
460+
461+ // Helper function to get the closest span
462+ function getClosestSpan ( node ) {
463+ while ( node && node . nodeType !== Node . ELEMENT_NODE ) {
464+ node = node . parentNode ;
471465 }
472- parentElement = parentElement . parentElement ;
466+ return node . closest ( 'span[data-m][data-d]' ) ;
473467 }
474468
475- if ( selection . toString ( ) !== '' && insideTranscript === true && selection . focusNode !== null && selection . anchorNode !== null ) {
476-
477- let fNode = selection . focusNode . parentNode ;
478- let aNode = selection . anchorNode . parentNode ;
469+ // Get all relevant spans
470+ const allSpans = Array . from ( document . querySelectorAll ( 'span[data-m][data-d]' ) ) ;
479471
480- if ( aNode . tagName === "P" ) {
481- aNode = selection . anchorNode . nextElementSibling ;
482- }
472+ // Find the first and last span that contain selected text
473+ let startSpan = null ;
474+ let endSpan = null ;
475+ let selectedText = range . toString ( ) ;
476+ let trimmedSelectedText = selectedText . trim ( ) ;
483477
484- if ( fNode . tagName === "P" ) {
485- fNode = selection . focusNode . nextElementSibling ;
478+ for ( let span of allSpans ) {
479+ if ( range . intersectsNode ( span ) && span . textContent . trim ( ) !== '' ) {
480+ if ( ! startSpan ) startSpan = span ;
481+ endSpan = span ;
486482 }
483+ }
487484
488- if ( aNode . getAttribute ( 'data-m' ) === null || aNode . className === 'speaker' ) {
489- aNode = aNode . nextElementSibling ;
490- }
491-
492- if ( fNode . getAttribute ( 'data-m' ) === null || fNode . className === 'speaker' ) {
493- fNode = fNode . previousElementSibling ;
494- }
495-
496- // if the selection starts with a space we want the next element
497- if ( selection . toString ( ) . charAt ( 0 ) == " " && aNode !== null ) {
498- aNode = aNode . nextElementSibling ;
499- }
500-
501- if ( aNode !== null ) {
502- let aNodeTime = parseInt ( aNode . getAttribute ( 'data-m' ) , 10 ) ;
503- let aNodeDuration = parseInt ( aNode . getAttribute ( 'data-d' ) , 10 ) ;
504- let fNodeTime ;
505- let fNodeDuration ;
506-
507- if ( fNode !== null && fNode . getAttribute ( 'data-m' ) !== null ) {
508- // if the selection ends in a space we want the previous element if it exists
509- if ( selection . toString ( ) . slice ( - 1 ) == " " && fNode . previousElementSibling !== null ) {
510- fNode = fNode . previousElementSibling ;
511- }
512-
513- fNodeTime = parseInt ( fNode . getAttribute ( 'data-m' ) , 10 ) ;
514- fNodeDuration = parseInt ( fNode . getAttribute ( 'data-d' ) , 10 ) ;
515-
516- // if the selection starts with a space we want the next element
485+ if ( ! startSpan || ! endSpan ) return null ;
517486
518- }
487+ // Adjust start span if selection starts with a space
488+ let startIndex = allSpans . indexOf ( startSpan ) ;
489+ while ( selectedText . startsWith ( ' ' ) && startIndex < allSpans . length - 1 ) {
490+ startIndex ++ ;
491+ startSpan = allSpans [ startIndex ] ;
492+ selectedText = selectedText . slice ( 1 ) ;
493+ }
519494
520- // 1 decimal place will do
521- aNodeTime = Math . round ( aNodeTime / 100 ) / 10 ;
522- aNodeDuration = Math . round ( aNodeDuration / 100 ) / 10 ;
523- fNodeTime = Math . round ( fNodeTime / 100 ) / 10 ;
524- fNodeDuration = Math . round ( fNodeDuration / 100 ) / 10 ;
495+ // Calculate start time
496+ let startTime = parseInt ( startSpan . dataset . m ) / 1000 ;
525497
526- let nodeStart = aNodeTime ;
527- let nodeDuration = Math . round ( ( fNodeTime + fNodeDuration - aNodeTime ) * 10 ) / 10 ;
498+ // Calculate end time
499+ let endTime = ( parseInt ( endSpan . dataset . m ) + parseInt ( endSpan . dataset . d ) ) / 1000 ;
528500
529- if ( aNodeTime >= fNodeTime ) {
530- nodeStart = fNodeTime ;
531- nodeDuration = Math . round ( ( aNodeTime + aNodeDuration - fNodeTime ) * 10 ) / 10 ;
532- }
501+ // Format to seconds at 2 decimal place precision
502+ let startTimeFormatted = ( Math . round ( startTime * 100 ) / 100 ) . toFixed ( 2 ) ;
503+ let endTimeFormatted = ( Math . round ( endTime * 100 ) / 100 ) . toFixed ( 2 ) ;
533504
534- if ( nodeDuration === 0 || nodeDuration === null || isNaN ( nodeDuration ) ) {
535- nodeDuration = 10 ; // arbitary for now
536- }
505+ // Only return a range if there's actually selected text (excluding only spaces)
506+ return trimmedSelectedText ? ` ${ startTimeFormatted } , ${ endTimeFormatted } ` : null ;
507+ }
537508
538- if ( isNaN ( parseFloat ( nodeStart ) ) ) {
539- fragment = null ;
540- } else {
541- fragment = this . transcript . id + '=' + nodeStart + ',' + Math . round ( ( nodeStart + nodeDuration ) * 10 ) / 10 ;
542- }
543- }
509+ getSelectionMediaFragment = ( ) => {
510+ let range = this . getSelectionRange ( ) ;
511+ if ( range === null ) {
512+ return null ;
544513 }
545-
546- return fragment ;
547- } ;
514+ return ( this . transcript . id + '=' + range ) ;
515+ }
548516
549517 setPlayHead = e => {
550518 const target = e . target ? e . target : e . srcElement ;
@@ -852,4 +820,4 @@ if (typeof module !== 'undefined' && module.exports) {
852820 module . exports = { HyperaudioLite } ;
853821}
854822
855- //export default HyperaudioLite;
823+ //export default HyperaudioLite;
0 commit comments