Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions playwright-tests/tests/blocksTests.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ test.describe("Issues", () => {
await page
.getByTestId("action-block")
.filter({ hasText: 'Code preview: print("hello")' })
.getByRole("button")
.nth(2)
.getByTestId(/^action-checkbox/)
.click(); //uncheck codeblock
await configPage.removeAction();

Expand Down
23 changes: 21 additions & 2 deletions src/renderer/config-blocks/CodeBlock.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
import SendFeedback from "../main/user-interface/SendFeedback.svelte";

import { MoltenPushButton } from "@intechstudio/grid-uikit";
import { copyContextMenu } from "../main/_actions/copy-context-menu.action";
import MoltenPopup from "../main/panels/preferences/MoltenPopup.svelte";

import { Modal } from "../main/modals/modal.store";
import Monaco from "../main/modals/Monaco.svelte";
Expand Down Expand Up @@ -121,13 +123,30 @@
<div class="grid w-full">
<pre
on:dblclick={open_monaco}
class="bg-black/25 my-4 p-2 w-full overflow-x-auto border border-black"
use:copyContextMenu
class="bg-black/25 my-4 p-2 w-full overflow-x-auto border border-black select-text"
bind:this={codePreview}
data-lang="intech_lua"
/>
</div>

<MoltenPushButton click={open_monaco} text={"Edit Code"} style={"accept"} />
<div class="flex flex-row gap-2">
<MoltenPushButton
click={open_monaco}
text={"Edit Code"}
style={"accept"}
/>
<div class="flex-grow" />
<MoltenPushButton
click={() =>
navigator.clipboard.writeText(
GridScript.expandScript($action.script),
)}
text={"Copy Code"}
>
<MoltenPopup slot="popup" text="Copied to clipboard!" />
</MoltenPushButton>
</div>
</div>

<div class="flex flex-row mt-4">
Expand Down
110 changes: 110 additions & 0 deletions src/renderer/main/_actions/copy-context-menu.action.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
const INLINE_TAGS = new Set([
"span",
"a",
"em",
"strong",
"b",
"i",
"u",
"code",
]);

function getTextFromNode(node: Node): string {
if (node.nodeType === Node.TEXT_NODE) {
return node.textContent ?? "";
}
if (node.nodeType !== Node.ELEMENT_NODE) return "";

const el = node as HTMLElement;
const tag = el.tagName.toLowerCase();
const childTexts = Array.from(el.childNodes).map(getTextFromNode);

// Grid rows: join cells inline with spaces
if (el.className?.includes?.("grid-cols")) {
return childTexts.filter((s) => s.trim().length > 0).join(" ");
}

// Flex rows that are direct data rows (not layout wrappers): join inline
if (el.className?.includes?.("flex-row") && el.className?.includes?.("gap")) {
return childTexts.filter((s) => s.trim().length > 0).join(" ");
}

// Inline elements: join without separator to preserve token continuity
if (INLINE_TAGS.has(tag)) {
return childTexts.join("");
}

// Block elements: join with newlines
return childTexts.filter((s) => s.trim().length > 0).join("\n");
}

function getSelectionText(): string {
const selection = window.getSelection();
if (!selection || selection.rangeCount === 0) return "";

const range = selection.getRangeAt(0);
const fragment = range.cloneContents();

const texts = Array.from(fragment.childNodes)
.map(getTextFromNode)
.filter((s) => s.length > 0);

return texts.join("\n").trim();
}

export function copyContextMenu(node: HTMLElement) {
let menu: HTMLElement | null = null;

function removeMenu() {
menu?.remove();
menu = null;
}

function handleContextMenu(e: MouseEvent) {
e.preventDefault();
e.stopPropagation();
removeMenu();

menu = document.createElement("div");
menu.className =
"fixed z-50 bg-primary border border-gray-600 rounded shadow-lg py-1 text-sm text-white";
menu.style.left = `${e.clientX}px`;
menu.style.top = `${e.clientY}px`;

const button = document.createElement("button");
button.textContent = "Copy";
button.className = "w-full text-left px-4 py-1 hover:bg-gray-700";
button.onclick = () => {
navigator.clipboard.writeText(getSelectionText());
removeMenu();
};

menu.appendChild(button);
document.body.appendChild(menu);
}

function handleCopy(e: ClipboardEvent) {
const text = getSelectionText();
if (text) {
e.clipboardData?.setData("text/plain", text);
e.preventDefault();
}
}

function handleClick() {
removeMenu();
}

node.addEventListener("contextmenu", handleContextMenu);
node.addEventListener("copy", handleCopy);
window.addEventListener("click", handleClick);

return {
destroy() {
node.removeEventListener("contextmenu", handleContextMenu);
node.removeEventListener("copy", handleCopy);
window.removeEventListener("click", handleClick);
removeMenu();
},
};
}
2 changes: 2 additions & 0 deletions src/renderer/main/panels/DebugMonitor/DebugMonitor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import DebugTextList from "./DebugTextList.svelte";
import { scrollToBottom } from "../../_actions/scroll.move";
import SendImmediate from "./SendImmediate.svelte";
import { copyContextMenu } from "../../_actions/copy-context-menu.action";
import SendEvaluate from "./SendEvaluate.svelte";
import SendRaw from "./SendRaw.svelte";

Expand Down Expand Up @@ -255,6 +256,7 @@
<div
class="flex flex-grow w-full selectable overflow-y-auto p-1"
use:scrollToBottom={debug_lowlevel_store}
use:copyContextMenu
>
<div class=" flex flex-col min-h-[100px] font-mono text-white">
{#each $debug_lowlevel_store as debug, i}
Expand Down
4 changes: 3 additions & 1 deletion src/renderer/main/panels/DebugMonitor/DebugTextList.svelte
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script lang="ts">
import { debug_monitor_store } from "./DebugMonitor.store";
import { scrollToBottom } from "../../_actions/scroll.move";
import { copyContextMenu } from "../../_actions/copy-context-menu.action";
</script>

<container
Expand All @@ -9,7 +10,8 @@
>
<div
use:scrollToBottom={debug_monitor_store}
class="flex flex-col font-mono text-white bg-secondary p-2 flex-grow overflow-y-auto"
use:copyContextMenu
class="flex flex-col font-mono text-white bg-secondary p-2 flex-grow overflow-y-auto select-text"
>
{#each $debug_monitor_store as message}
{#each message.split("\n") as part}
Expand Down
10 changes: 7 additions & 3 deletions src/renderer/main/panels/MidiMonitor/MidiMonitor.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import { Grid } from "../../../lib/_utils";
import MidiTester from "./MidiTester.svelte";
import DebugTextList from "../DebugMonitor/DebugTextList.svelte";
import { copyContextMenu } from "../../_actions/copy-context-menu.action";
import { onDestroy, onMount, tick } from "svelte";
import {
type MidiWorkerCommand,
Expand Down Expand Up @@ -325,7 +326,8 @@
</div>

<div
class="flex flex-col flex-grow bg-secondary w-full overflow-clip"
class="flex flex-col flex-grow bg-secondary w-full overflow-clip select-text"
use:copyContextMenu
bind:clientHeight={debugMessageListHeight}
>
{#if lastMidiMessageIndex > 0}
Expand Down Expand Up @@ -386,7 +388,8 @@
{:else}
<div class="flex w-full text-white pb-2">MIDI Messages</div>
<div
class="flex h-full bg-secondary w-full overflow-clip"
class="flex h-full bg-secondary w-full overflow-clip select-text"
use:copyContextMenu
bind:clientHeight={midiMessageListHeight}
>
{#if lastMidiMessageIndex > 0}
Expand Down Expand Up @@ -492,7 +495,8 @@
System Exclusive Messages
</div>
<div
class="flex h-full bg-secondary w-full overflow-clip"
class="flex h-full bg-secondary w-full overflow-clip select-text"
use:copyContextMenu
bind:clientHeight={sysExMessageListHeight}
>
{#if lastSysExMessageIndex > 0}
Expand Down
Loading