Skip to content

Commit

Permalink
fix(code-review): 双栏模式下支持半边选中文本 (#1931) (#1932)
Browse files Browse the repository at this point in the history
* fix(code-review): 双栏模式下支持半边选中文本
  • Loading branch information
GreatZPP authored Jan 23, 2025
1 parent de8d758 commit a2a134a
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 6 deletions.
12 changes: 12 additions & 0 deletions packages/devui-vue/devui/code-review/src/code-review.scss
Original file line number Diff line number Diff line change
Expand Up @@ -304,4 +304,16 @@
box-shadow: 0 0 1px 1px rgba(37, 43, 58, 0.16);
cursor: pointer;
}

&--left-selected {
.d-code-right span {
user-select: none;
}
}

&--right-selected {
.d-code-left span {
user-select: none;
}
}
}
5 changes: 3 additions & 2 deletions packages/devui-vue/devui/code-review/src/code-review.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ export default defineComponent({
updateLineNumberMap,
updateCheckedLine,
} = useCodeReviewComment(reviewContentRef, props, ctx);
const { renderHtml, diffFile, onContentClick } = useCodeReview(props, ctx, reviewContentRef, updateLineNumberMap, updateCheckedLine);
const { renderHtml, diffFile, selectionSide, onContentClick } =
useCodeReview(props, ctx, reviewContentRef, updateLineNumberMap, updateCheckedLine);
const { isFold, toggleFold } = useCodeReviewFold(props, ctx);

onMounted(() => {
Expand All @@ -51,7 +52,7 @@ export default defineComponent({
});

return () => (
<div class={ns.b()}>
<div class={[ns.b(), { [ns.m(`${selectionSide.value}-selected`)]: Boolean(selectionSide.value) }]}>
<CodeReviewHeader onClick={() => (isFold.value = !isFold.value)} />
<div v-show={!isFold.value}>
{props.showBlob ? (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { toRefs, ref, watch, nextTick } from 'vue';
import { toRefs, ref, watch, nextTick, onUnmounted } from 'vue';
import type { SetupContext, Ref } from 'vue';
import type { DiffFile } from 'diff2html/lib/types';
import * as Diff2Html from 'diff2html';
import { useNamespace } from '../../../shared/hooks/use-namespace';
import { inBrowser } from '../../../shared/utils/common-var';
import type { CodeReviewProps, IExpandLineNumberInfo } from '../code-review-types';
import { useCodeReviewExpand } from './use-code-review-expand';
import { parseDiffCode } from '../utils';
import { getSelectionParent, parseDiffCode } from '../utils';

export function useCodeReview(
props: CodeReviewProps,
Expand All @@ -17,6 +18,8 @@ export function useCodeReview(
const { diff, outputFormat, allowExpand, showBlob } = toRefs(props);
const renderHtml = ref('');
const diffFile: Ref<DiffFile[]> = ref([]);
const ns = useNamespace('code-review');
const selectionSide = ref('');
const { insertExpandButton, onExpandButtonClick } = useCodeReviewExpand(reviewContentRef, props, updateLineNumberMap, updateCheckedLine);

const initDiffContent = () => {
Expand All @@ -34,11 +37,73 @@ export function useCodeReview(
onExpandButtonClick(e, props.options);
};

function onSelectionChange() {
if (selectionSide.value) {
return;
}
if (typeof window === 'undefined') {
return;
}
const selection = window.getSelection();
if (selection?.toString() && selection?.anchorNode) {
const side = getSelectionParent(selection.anchorNode as HTMLElement);
if (side) {
selectionSide.value = side;
}
}
}
function onMousedown(e: Event) {
if (typeof window === 'undefined') {
return;
}
const selection = window.getSelection();
const composedPath = e.composedPath();
const isLineNumber = composedPath.some((item: HTMLElement) => item.classList?.contains('d2h-code-side-linenumber'));
const isClickInner = composedPath.some((item: HTMLElement) => item.classList?.contains(ns.e('content')));
const clickSide = getSelectionParent(e.target as HTMLElement);
if (selection && selection.toString()) {
const isInRange = selection?.getRangeAt(0).intersectsNode(e.target);
if (
!isInRange ||
!isClickInner ||
(clickSide === 'left' && selectionSide.value === 'right') ||
(clickSide === 'right' && selectionSide.value === 'left') ||
isLineNumber
) {
setTimeout(() => {
selectionSide.value = '';
selection.removeAllRanges();
});
}
} else {
selectionSide.value = '';
}
}

watch(showBlob, initDiffContent);

watch(outputFormat, initDiffContent);

watch(diff, initDiffContent, { immediate: true });

return { renderHtml, diffFile, onContentClick };
watch(
() => props.outputFormat,
(val) => {
if (val === 'side-by-side') {
document.addEventListener('selectionchange', onSelectionChange);
document.addEventListener('mousedown', onMousedown, true);
} else {
document.removeEventListener('selectionchange', onSelectionChange);
document.removeEventListener('mousedown', onMousedown, true);
}
},
{ immediate: true }
);

onUnmounted(() => {
document.removeEventListener('selectionchange', onSelectionChange);
document.removeEventListener('mousedown', onMousedown, true);
});

return { renderHtml, diffFile, selectionSide, onContentClick };
}
18 changes: 18 additions & 0 deletions packages/devui-vue/devui/code-review/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -721,3 +721,21 @@ export function addCommentCheckedForSingle(

return result;
}

/* 双栏模式,选中文本时,根据选择的节点查找其父节点,用于判断左侧选中还是右侧选中 */
export function getSelectionParent(el: HTMLElement) {
if (el.tagName === 'TR') {
return;
}
if (el.tagName === 'TD' && (el.classList.contains('d-code-left') || el.classList.contains('d-code-right'))) {
if (el.classList.contains('d-code-left')) {
return 'left';
}
if (el.classList.contains('d-code-right')) {
return 'right';
}
}
if (el.parentElement) {
return getSelectionParent(el.parentElement);
}
}
2 changes: 1 addition & 1 deletion packages/devui-vue/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "vue-devui",
"version": "1.6.30",
"version": "1.6.31",
"license": "MIT",
"description": "DevUI components based on Vite and Vue3",
"keywords": [
Expand Down

0 comments on commit a2a134a

Please sign in to comment.