fix: cleanup dispatching contextMenu events

This commit is contained in:
ndom91 2024-06-06 14:11:46 +02:00
parent e062573c9f
commit dac1af917b
No known key found for this signature in database
3 changed files with 33 additions and 162 deletions

View File

@ -1,124 +0,0 @@
<script lang="ts">
import { create } from '$lib/components/Differ/CodeHighlighter';
import { SectionType } from '$lib/utils/fileSections';
import { createEventDispatcher } from 'svelte';
import type { Line } from '$lib/utils/fileSections';
export let line: Line;
export let sectionType: SectionType;
export let filePath: string;
export let minWidth = 1.75;
export let selectable: boolean = false;
export let selected: boolean = true;
export let readonly: boolean = false;
export let draggingDisabled: boolean = false;
export let tabSize = 4;
const dispatch = createEventDispatcher<{ selected: boolean }>();
function toTokens(codeString: string): string[] {
function sanitize(text: string) {
var element = document.createElement('div');
element.innerText = text;
return element.innerHTML;
}
let highlighter = create(codeString, filePath);
let tokens: string[] = [];
highlighter.highlight((text, classNames) => {
const token = classNames
? `<span class=${classNames}>${sanitize(text)}</span>`
: sanitize(text);
tokens.push(token);
});
return tokens;
}
$: isSelected = selectable && selected;
</script>
<div class="code-line" role="group" style="--tab-size: {tabSize}" on:contextmenu|preventDefault>
<div class="code-line__numbers-line">
<button
on:click={() => selectable && dispatch('selected', !selected)}
class="numbers-line-count"
class:selected={isSelected}
style:min-width={minWidth + 'rem'}
style:cursor={draggingDisabled ? 'default' : 'grab'}
>
{line.beforeLineNumber || ''}
</button>
<button
on:click={() => selectable && dispatch('selected', !selected)}
class="numbers-line-count"
class:selected={isSelected}
style:min-width={minWidth + 'rem'}
style:cursor={draggingDisabled ? 'default' : 'grab'}
>
{line.afterLineNumber || ''}
</button>
</div>
<div
class="line"
class:readonly
class:diff-line-deletion={sectionType === SectionType.RemovedLines}
class:diff-line-addition={sectionType === SectionType.AddedLines}
style:cursor={draggingDisabled ? 'default' : 'grab'}
>
<span class="selectable-wrapper" data-no-drag>
{@html toTokens(line.content).join('')}
</span>
</div>
</div>
<style lang="postcss">
.code-line {
display: flex;
width: 100%;
min-width: max-content;
font-family: monospace;
background-color: var(--clr-bg-1);
white-space: pre;
tab-size: var(--tab-size);
font-size: 11px;
line-height: 1.5;
}
.line {
flex-grow: 1;
}
.code-line__numbers-line {
position: sticky;
left: 0;
display: flex;
}
.numbers-line-count {
color: var(--clr-text-3);
border-color: var(--clr-border-2);
background-color: var(--clr-bg-1-muted);
font-size: 10px;
flex-shrink: 0;
user-select: none;
border-right-width: 1px;
padding-left: 2px;
padding-right: 2px;
text-align: right;
&.selected {
background-color: var(--hunk-line-selected-bg);
border-color: var(--hunk-line-selected-border);
color: white;
}
}
.selectable-wrapper {
cursor: text;
display: inline-block;
text-indent: 4px;
margin-right: 4px;
}
</style>

View File

@ -1,14 +1,8 @@
<script lang="ts">
import HunkContextMenu from './HunkContextMenu.svelte';
import { Project } from '$lib/backend/projects';
import { create } from '$lib/components/Differ/CodeHighlighter';
import { getContext } from '$lib/utils/context';
import { SectionType } from '$lib/utils/fileSections';
import { onDestroy } from 'svelte';
import { createEventDispatcher } from 'svelte';
import type { Line } from '$lib/utils/fileSections';
import type { ContentSection } from '$lib/utils/fileSections';
import type { Hunk } from '$lib/vbranches/types';
export let lines: Line[];
export let sectionType: SectionType;
@ -19,26 +13,14 @@
export let readonly: boolean = false;
export let draggingDisabled: boolean = false;
export let tabSize = 4;
export let hunk: Hunk;
export let subsection: ContentSection;
$: isSelected = selectable && selected;
$: popupMenu = updateContextMenu(filePath);
const project = getContext(Project);
const dispatch = createEventDispatcher<{
lineContextMenu: { lineNumber: number | undefined; event: MouseEvent };
selected: boolean;
}>();
function updateContextMenu(filePath: string) {
if (popupMenu) popupMenu.$destroy();
return new HunkContextMenu({
target: document.body,
props: { projectPath: project.vscodePath, filePath, readonly }
});
}
function toTokens(inputLine: string): string[] {
function sanitize(text: string) {
var element = document.createElement('div');
@ -57,12 +39,6 @@
});
return tokens;
}
onDestroy(() => {
if (popupMenu) {
popupMenu.$destroy();
}
});
</script>
<div
@ -75,15 +51,11 @@
<div
class="code-line"
role="group"
on:contextmenu={(e) => {
on:contextmenu={(event) => {
const lineNumber = line.afterLineNumber
? line.afterLineNumber
: line.beforeLineNumber;
popupMenu.openByMouse(e, {
hunk,
lineNumber,
section: subsection
});
dispatch('lineContextMenu', { event, lineNumber });
}}
>
<div class="code-line__numbers-line">

View File

@ -1,19 +1,22 @@
<script lang="ts">
import HunkSection from './HunkSection.svelte';
import HunkContextMenu from './HunkContextMenu.svelte';
import HunkLines from './HunkLines.svelte';
import LargeDiffMessage from './LargeDiffMessage.svelte';
import { Project } from '$lib/backend/projects';
import { draggable } from '$lib/dragging/draggable';
import { DraggableHunk } from '$lib/dragging/draggables';
import { SETTINGS, type Settings } from '$lib/settings/userSettings';
import { getContextStoreBySymbol, maybeGetContextStore } from '$lib/utils/context';
import { getContext, getContextStoreBySymbol, maybeGetContextStore } from '$lib/utils/context';
import { Ownership } from '$lib/vbranches/ownership';
import { Branch, type Hunk } from '$lib/vbranches/types';
import type { HunkSection as HunkSectionType } from '$lib/utils/fileSections';
import { onDestroy } from 'svelte';
import type { HunkSection } from '$lib/utils/fileSections';
import type { Writable } from 'svelte/store';
export let viewport: HTMLDivElement | undefined = undefined;
export let contents: HTMLDivElement | undefined = undefined;
export let filePath: string;
export let section: HunkSectionType;
export let section: HunkSection;
export let minWidth: number;
export let selectable = false;
export let isUnapplied: boolean;
@ -24,6 +27,7 @@
const selectedOwnership: Writable<Ownership> | undefined = maybeGetContextStore(Ownership);
const userSettings = getContextStoreBySymbol<Settings>(SETTINGS);
const branch = maybeGetContextStore(Branch);
const project = getContext(Project);
function onHunkSelected(hunk: Hunk, isSelected: boolean) {
if (!selectedOwnership) return;
@ -33,9 +37,23 @@
selectedOwnership.update((ownership) => ownership.remove(hunk.filePath, hunk.id));
}
}
function updateContextMenu(filePath: string) {
if (popupMenu) popupMenu.$destroy();
return new HunkContextMenu({
target: document.body,
props: { projectPath: project.vscodePath, filePath, readonly }
});
}
$: popupMenu = updateContextMenu(filePath);
$: draggingDisabled = readonly || isUnapplied;
onDestroy(() => {
if (popupMenu) {
popupMenu.$destroy();
}
});
let alwaysShow = false;
</script>
@ -63,19 +81,24 @@
{:else}
{#each section.subSections as subsection}
{@const hunk = section.hunk}
<HunkSection
<HunkLines
lines={subsection.lines}
{filePath}
{readonly}
{minWidth}
{selectable}
{draggingDisabled}
{hunk}
{subsection}
tabSize={$userSettings.tabSize}
selected={$selectedOwnership?.contains(hunk.filePath, hunk.id)}
on:selected={(e) => onHunkSelected(hunk, e.detail)}
sectionType={subsection.sectionType}
on:lineContextMenu={(e) => {
popupMenu.openByMouse(e.detail.event, {
hunk,
section: subsection,
lineNumber: e.detail.lineNumber
});
}}
/>
{/each}
{/if}