@@ -282,35 +282,61 @@ function parseData2(data) {
282282
283283 if ( selections != null && selections . length != 0 ) {
284284 selections . forEach ( function ( selection ) {
285- let selectionMatches = sourceMatches + selection . getAttribute ( "creatingUser" ) + selection . getAttribute ( "modifyingUser" ) ;
286- selectionMatches = selectionMatches + getCodeRelatedGUIDs ( selection ) ;
287-
288- // Get position information for PlainTextSelection
289- let selectionName = selection . getAttribute ( "name" ) ;
290- let startPos = selection . getAttribute ( "startPosition" ) ;
291- let endPos = selection . getAttribute ( "endPosition" ) ;
292- let plainTextPath = source . getAttribute ( "plainTextPath" ) ;
293- let sourceGuid = source . getAttribute ( "guid" ) ;
294-
295- // Create tooltip-enabled name if we have position data
296- let displayName = selectionName ;
297- if ( selection . nodeName === "PDFSelection" ) {
298- let page = selection . getAttribute ( "page" ) ;
299- let firstX = selection . getAttribute ( "firstX" ) ;
300- let firstY = selection . getAttribute ( "firstY" ) ;
301- let secondX = selection . getAttribute ( "secondX" ) ;
302- let secondY = selection . getAttribute ( "secondY" ) ;
303- displayName = createPdfSelectionWithTooltip ( selectionName , page , firstX , firstY , secondX , secondY , sourceGuid ) ;
304- } else if ( selection . nodeName === "PlainTextSelection" && startPos && endPos && plainTextPath ) {
305- displayName = createSelectionWithTooltip ( selectionName , startPos , endPos , plainTextPath , sourceGuid ) ;
285+ let displayName ;
286+ let selectionMatches ;
287+ let guid ;
288+ let codes ;
289+
290+ if ( selection . isMerged ) {
291+ // Handle merged selection object
292+ let pdfSel = selection . pdfSelection ;
293+ let textSel = selection . plainTextSelection ;
294+ let selectionName = pdfSel . getAttribute ( "name" ) ;
295+ guid = pdfSel . getAttribute ( "guid" ) ;
296+ codes = getCodeNames ( pdfSel ) ; // Codes are on the PDF selection
297+
298+ selectionMatches = sourceMatches +
299+ pdfSel . getAttribute ( "creatingUser" ) + pdfSel . getAttribute ( "modifyingUser" ) +
300+ textSel . getAttribute ( "creatingUser" ) + textSel . getAttribute ( "modifyingUser" ) +
301+ getCodeRelatedGUIDs ( pdfSel ) ;
302+
303+ let sourceGuid = source . getAttribute ( "guid" ) ;
304+
305+ displayName = createMergedSelectionWithTooltip ( selectionName , pdfSel , textSel , sourceGuid ) ;
306+
307+ } else {
308+ // Handle regular selection node
309+ let selectionName = selection . getAttribute ( "name" ) ;
310+ guid = selection . getAttribute ( "guid" ) ;
311+ codes = getCodeNames ( selection ) ;
312+ selectionMatches = sourceMatches + selection . getAttribute ( "creatingUser" ) + selection . getAttribute ( "modifyingUser" ) + getCodeRelatedGUIDs ( selection ) ;
313+
314+ let sourceGuid = source . getAttribute ( "guid" ) ;
315+ displayName = selectionName ; // Default display name
316+
317+ if ( selection . nodeName === "PDFSelection" ) {
318+ let page = selection . getAttribute ( "page" ) ;
319+ let firstX = selection . getAttribute ( "firstX" ) ;
320+ let firstY = selection . getAttribute ( "firstY" ) ;
321+ let secondX = selection . getAttribute ( "secondX" ) ;
322+ let secondY = selection . getAttribute ( "secondY" ) ;
323+ displayName = createPdfSelectionWithTooltip ( selectionName , page , firstX , firstY , secondX , secondY , sourceGuid ) ;
324+ } else if ( selection . nodeName === "PlainTextSelection" ) {
325+ let startPos = selection . getAttribute ( "startPosition" ) ;
326+ let endPos = selection . getAttribute ( "endPosition" ) ;
327+ let plainTextPath = source . getAttribute ( "plainTextPath" ) ;
328+ if ( startPos && endPos && plainTextPath ) {
329+ displayName = createSelectionWithTooltip ( selectionName , startPos , endPos , plainTextPath , sourceGuid ) ;
330+ }
331+ }
306332 }
307333
308334 annotationRows . push ( {
309- sourceRef : createSourceReference ( source ) ,
335+ sourceRef : createSourceReference ( source , zipUrl ) ,
310336 type : source . nodeName ,
311337 name : displayName ,
312- codes : getCodeNames ( selection ) ,
313- guid : selection . getAttribute ( " guid" ) ,
338+ codes : codes ,
339+ guid : guid ,
314340 matches : selectionMatches
315341 } ) ;
316342 } ) ;
@@ -791,12 +817,44 @@ function createRefiqdaFilterFunction(dataTable) {
791817}
792818
793819function getSelections ( source ) {
794- let children = source . getElementsByTagName ( "*" ) ;
795820 let selections = [ ] ;
796- for ( let child of children ) {
797- if ( child . nodeName . endsWith ( "Selection" ) ) {
798- // console.log(child.getAttribute("name"));
799- selections . push ( child ) ;
821+ // If it's a PDF source, we look for both PDF and PlainText selections to merge them
822+ if ( source . nodeName === "PDFSource" ) {
823+ const representation = source . querySelector ( "Representation" ) ;
824+ const plainTextSelections = new Map ( ) ;
825+
826+ // Map PlainTextSelections by their GUID from the Representation, if it exists
827+ if ( representation ) {
828+ for ( const pts of representation . getElementsByTagName ( "PlainTextSelection" ) ) {
829+ plainTextSelections . set ( pts . getAttribute ( "guid" ) , pts ) ;
830+ }
831+ }
832+
833+ // Process PDFSelections
834+ for ( const pdfSel of source . getElementsByTagName ( "PDFSelection" ) ) {
835+ const guid = pdfSel . getAttribute ( "guid" ) ;
836+ const matchingPlainTextSel = plainTextSelections . get ( guid ) ;
837+
838+ if ( matchingPlainTextSel ) {
839+ // Found a pair, create a merged object
840+ selections . push ( {
841+ isMerged : true ,
842+ pdfSelection : pdfSel ,
843+ plainTextSelection : matchingPlainTextSel
844+ } ) ;
845+ // Remove from map so we don't process it again
846+ plainTextSelections . delete ( guid ) ;
847+ } else {
848+ // It's a PDF-only selection
849+ selections . push ( pdfSel ) ;
850+ }
851+ }
852+ } else {
853+ // For other source types, get direct children ending in "Selection"
854+ for ( const child of source . children ) {
855+ if ( child . nodeName . endsWith ( "Selection" ) ) {
856+ selections . push ( child ) ;
857+ }
800858 }
801859 }
802860 return selections ;
@@ -816,18 +874,18 @@ function getCodeRelatedGUIDs(selection) {
816874}
817875
818876function getCodeNames ( selection ) {
819- let codeNames = '' ;
877+ let codeNameList = [ ] ;
820878 let codings = selection . getElementsByTagName ( "Coding" ) ;
821879 if ( codings != null ) {
822880 for ( let coding of codings ) {
823881 let codeId = coding . getElementsByTagName ( "CodeRef" ) [ 0 ] . getAttribute ( "targetGUID" ) ;
824882 let code = codeMap . get ( codeId ) ;
825883 if ( code != null ) {
826- codeNames = codeNames + ' ' + code . getAttribute ( "name" ) ;
884+ codeNameList . push ( code . getAttribute ( "name" ) ) ;
827885 }
828886 }
829887 }
830- return codeNames ;
888+ return codeNameList . join ( ', ' ) ;
831889}
832890
833891// Update the createSelectionWithTooltip function to use a simpler data structure
@@ -844,6 +902,39 @@ function createSelectionWithTooltip(selectionName, startPos, endPos, plainTextPa
844902 return spanHtml ;
845903}
846904
905+ function createMergedSelectionWithTooltip ( selectionName , pdfSel , plainTextSel , sourceGuid ) {
906+ // Extract data from both selection types
907+ const page = pdfSel . getAttribute ( "page" ) ;
908+ const firstX = pdfSel . getAttribute ( "firstX" ) ;
909+ const firstY = pdfSel . getAttribute ( "firstY" ) ;
910+ const secondX = pdfSel . getAttribute ( "secondX" ) ;
911+ const secondY = pdfSel . getAttribute ( "secondY" ) ;
912+
913+ const startPos = plainTextSel . getAttribute ( "startPosition" ) ;
914+ const endPos = plainTextSel . getAttribute ( "endPosition" ) ;
915+ const plainTextPath = plainTextSel . closest ( "Representation" ) . getAttribute ( "plainTextPath" ) ;
916+
917+ // Create the HTML content for the Tippy tooltip
918+ let tooltipContent = `Page: ${ page } (X:${ firstX } , Y:${ firstY } ) to (X:${ secondX } , Y:${ secondY } )` ;
919+
920+ // Create a span with data attributes for both PDF and Text functionality
921+ let spanHtml = '<span class="selection-with-excerpt selection-with-pdf-coords" ' +
922+ 'data-tippy-content="' + tooltipContent + '" ' +
923+ 'data-page="' + page + '" ' +
924+ 'data-first-x="' + firstX + '" ' +
925+ 'data-first-y="' + firstY + '" ' +
926+ 'data-second-x="' + secondX + '" ' +
927+ 'data-second-y="' + secondY + '" ' +
928+ 'data-start="' + startPos + '" ' +
929+ 'data-end="' + endPos + '" ' +
930+ 'data-path="' + plainTextPath + '" ' +
931+ 'data-source-guid="' + sourceGuid + '">' +
932+ selectionName +
933+ '</span>' ;
934+
935+ return spanHtml ;
936+ }
937+
847938function createPdfSelectionWithTooltip ( selectionName , page , firstX , firstY , secondX , secondY , sourceGuid ) {
848939 // Create the HTML content for the Tippy tooltip
849940 let tooltipContent = `Page: ${ page } <br>From: (X:${ firstX } , Y:${ firstY } )<br>To: (X:${ secondX } , Y:${ secondY } )` ;
@@ -957,7 +1048,15 @@ function initializeExcerptTooltips() {
9571048 loadTextExcerpt ( plainTextPath , startPos , endPos , sourceGuid )
9581049 . then ( excerpt => {
9591050 if ( excerpt ) {
960- const formattedContent = formatExcerptTooltip ( excerpt , startPos , endPos ) ;
1051+ let formattedContent = formatExcerptTooltip ( excerpt , startPos , endPos ) ;
1052+ // For merged selections, prepend the PDF coordinate info
1053+ if ( element . classList . contains ( 'selection-with-pdf-coords' ) ) {
1054+ const pdfInfo = element . getAttribute ( 'data-tippy-content' ) ;
1055+ if ( pdfInfo ) {
1056+ const pdfHtml = `<div style="padding: 8px 8px 0 8px; font-family: sans-serif; font-size: 11px; color: #666;">${ pdfInfo } </div>` ;
1057+ formattedContent = pdfHtml + formattedContent ;
1058+ }
1059+ }
9611060 instance . setContent ( formattedContent ) ;
9621061 element . setAttribute ( 'data-tooltip-loaded' , 'true' ) ;
9631062 } else {
0 commit comments