Skip to content

Commit a2a134a

Browse files
authored
fix(code-review): 双栏模式下支持半边选中文本 (#1931) (#1932)
* fix(code-review): 双栏模式下支持半边选中文本
1 parent de8d758 commit a2a134a

File tree

5 files changed

+102
-6
lines changed

5 files changed

+102
-6
lines changed

packages/devui-vue/devui/code-review/src/code-review.scss

+12
Original file line numberDiff line numberDiff line change
@@ -304,4 +304,16 @@
304304
box-shadow: 0 0 1px 1px rgba(37, 43, 58, 0.16);
305305
cursor: pointer;
306306
}
307+
308+
&--left-selected {
309+
.d-code-right span {
310+
user-select: none;
311+
}
312+
}
313+
314+
&--right-selected {
315+
.d-code-left span {
316+
user-select: none;
317+
}
318+
}
307319
}

packages/devui-vue/devui/code-review/src/code-review.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ export default defineComponent({
3131
updateLineNumberMap,
3232
updateCheckedLine,
3333
} = useCodeReviewComment(reviewContentRef, props, ctx);
34-
const { renderHtml, diffFile, onContentClick } = useCodeReview(props, ctx, reviewContentRef, updateLineNumberMap, updateCheckedLine);
34+
const { renderHtml, diffFile, selectionSide, onContentClick } =
35+
useCodeReview(props, ctx, reviewContentRef, updateLineNumberMap, updateCheckedLine);
3536
const { isFold, toggleFold } = useCodeReviewFold(props, ctx);
3637

3738
onMounted(() => {
@@ -51,7 +52,7 @@ export default defineComponent({
5152
});
5253

5354
return () => (
54-
<div class={ns.b()}>
55+
<div class={[ns.b(), { [ns.m(`${selectionSide.value}-selected`)]: Boolean(selectionSide.value) }]}>
5556
<CodeReviewHeader onClick={() => (isFold.value = !isFold.value)} />
5657
<div v-show={!isFold.value}>
5758
{props.showBlob ? (

packages/devui-vue/devui/code-review/src/composables/use-code-review.ts

+68-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import { toRefs, ref, watch, nextTick } from 'vue';
1+
import { toRefs, ref, watch, nextTick, onUnmounted } from 'vue';
22
import type { SetupContext, Ref } from 'vue';
33
import type { DiffFile } from 'diff2html/lib/types';
44
import * as Diff2Html from 'diff2html';
5+
import { useNamespace } from '../../../shared/hooks/use-namespace';
56
import { inBrowser } from '../../../shared/utils/common-var';
67
import type { CodeReviewProps, IExpandLineNumberInfo } from '../code-review-types';
78
import { useCodeReviewExpand } from './use-code-review-expand';
8-
import { parseDiffCode } from '../utils';
9+
import { getSelectionParent, parseDiffCode } from '../utils';
910

1011
export 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
}

packages/devui-vue/devui/code-review/src/utils.ts

+18
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,21 @@ export function addCommentCheckedForSingle(
721721

722722
return result;
723723
}
724+
725+
/* 双栏模式,选中文本时,根据选择的节点查找其父节点,用于判断左侧选中还是右侧选中 */
726+
export function getSelectionParent(el: HTMLElement) {
727+
if (el.tagName === 'TR') {
728+
return;
729+
}
730+
if (el.tagName === 'TD' && (el.classList.contains('d-code-left') || el.classList.contains('d-code-right'))) {
731+
if (el.classList.contains('d-code-left')) {
732+
return 'left';
733+
}
734+
if (el.classList.contains('d-code-right')) {
735+
return 'right';
736+
}
737+
}
738+
if (el.parentElement) {
739+
return getSelectionParent(el.parentElement);
740+
}
741+
}

packages/devui-vue/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vue-devui",
3-
"version": "1.6.30",
3+
"version": "1.6.31",
44
"license": "MIT",
55
"description": "DevUI components based on Vite and Vue3",
66
"keywords": [

0 commit comments

Comments
 (0)