1- import { toRefs , ref , watch , nextTick } from 'vue' ;
1+ import { toRefs , ref , watch , nextTick , onUnmounted } from 'vue' ;
22import type { SetupContext , Ref } from 'vue' ;
33import type { DiffFile } from 'diff2html/lib/types' ;
44import * as Diff2Html from 'diff2html' ;
5+ import { useNamespace } from '../../../shared/hooks/use-namespace' ;
56import { inBrowser } from '../../../shared/utils/common-var' ;
67import type { CodeReviewProps , IExpandLineNumberInfo } from '../code-review-types' ;
78import { useCodeReviewExpand } from './use-code-review-expand' ;
8- import { parseDiffCode } from '../utils' ;
9+ import { getSelectionParent , parseDiffCode } from '../utils' ;
910
1011export function useCodeReview (
1112 props : CodeReviewProps ,
@@ -17,6 +18,8 @@ export function useCodeReview(
1718 const { diff, outputFormat, allowExpand, showBlob } = toRefs ( props ) ;
1819 const renderHtml = ref ( '' ) ;
1920 const diffFile : Ref < DiffFile [ ] > = ref ( [ ] ) ;
21+ const ns = useNamespace ( 'code-review' ) ;
22+ const selectionSide = ref ( '' ) ;
2023 const { insertExpandButton, onExpandButtonClick } = useCodeReviewExpand ( reviewContentRef , props , updateLineNumberMap , updateCheckedLine ) ;
2124
2225 const initDiffContent = ( ) => {
@@ -34,11 +37,73 @@ export function useCodeReview(
3437 onExpandButtonClick ( e , props . options ) ;
3538 } ;
3639
40+ function onSelectionChange ( ) {
41+ if ( selectionSide . value ) {
42+ return ;
43+ }
44+ if ( typeof window === 'undefined' ) {
45+ return ;
46+ }
47+ const selection = window . getSelection ( ) ;
48+ if ( selection ?. toString ( ) && selection ?. anchorNode ) {
49+ const side = getSelectionParent ( selection . anchorNode as HTMLElement ) ;
50+ if ( side ) {
51+ selectionSide . value = side ;
52+ }
53+ }
54+ }
55+ function onMousedown ( e : Event ) {
56+ if ( typeof window === 'undefined' ) {
57+ return ;
58+ }
59+ const selection = window . getSelection ( ) ;
60+ const composedPath = e . composedPath ( ) ;
61+ const isLineNumber = composedPath . some ( ( item : HTMLElement ) => item . classList ?. contains ( 'd2h-code-side-linenumber' ) ) ;
62+ const isClickInner = composedPath . some ( ( item : HTMLElement ) => item . classList ?. contains ( ns . e ( 'content' ) ) ) ;
63+ const clickSide = getSelectionParent ( e . target as HTMLElement ) ;
64+ if ( selection && selection . toString ( ) ) {
65+ const isInRange = selection ?. getRangeAt ( 0 ) . intersectsNode ( e . target ) ;
66+ if (
67+ ! isInRange ||
68+ ! isClickInner ||
69+ ( clickSide === 'left' && selectionSide . value === 'right' ) ||
70+ ( clickSide === 'right' && selectionSide . value === 'left' ) ||
71+ isLineNumber
72+ ) {
73+ setTimeout ( ( ) => {
74+ selectionSide . value = '' ;
75+ selection . removeAllRanges ( ) ;
76+ } ) ;
77+ }
78+ } else {
79+ selectionSide . value = '' ;
80+ }
81+ }
82+
3783 watch ( showBlob , initDiffContent ) ;
3884
3985 watch ( outputFormat , initDiffContent ) ;
4086
4187 watch ( diff , initDiffContent , { immediate : true } ) ;
4288
43- return { renderHtml, diffFile, onContentClick } ;
89+ watch (
90+ ( ) => props . outputFormat ,
91+ ( val ) => {
92+ if ( val === 'side-by-side' ) {
93+ document . addEventListener ( 'selectionchange' , onSelectionChange ) ;
94+ document . addEventListener ( 'mousedown' , onMousedown , true ) ;
95+ } else {
96+ document . removeEventListener ( 'selectionchange' , onSelectionChange ) ;
97+ document . removeEventListener ( 'mousedown' , onMousedown , true ) ;
98+ }
99+ } ,
100+ { immediate : true }
101+ ) ;
102+
103+ onUnmounted ( ( ) => {
104+ document . removeEventListener ( 'selectionchange' , onSelectionChange ) ;
105+ document . removeEventListener ( 'mousedown' , onMousedown , true ) ;
106+ } ) ;
107+
108+ return { renderHtml, diffFile, selectionSide, onContentClick } ;
44109}
0 commit comments