mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	feat(client): add a copy button to read-only text
This commit is contained in:
		@@ -9,7 +9,7 @@ import treeService from "./tree.js";
 | 
				
			|||||||
import FNote from "../entities/fnote.js";
 | 
					import FNote from "../entities/fnote.js";
 | 
				
			||||||
import FAttachment from "../entities/fattachment.js";
 | 
					import FAttachment from "../entities/fattachment.js";
 | 
				
			||||||
import imageContextMenuService from "../menus/image_context_menu.js";
 | 
					import imageContextMenuService from "../menus/image_context_menu.js";
 | 
				
			||||||
import { applySingleBlockSyntaxHighlight, applySyntaxHighlight } from "./syntax_highlight.js";
 | 
					import { applySingleBlockSyntaxHighlight, formatCodeBlocks } from "./syntax_highlight.js";
 | 
				
			||||||
import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
 | 
					import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
 | 
				
			||||||
import renderDoc from "./doc_renderer.js";
 | 
					import renderDoc from "./doc_renderer.js";
 | 
				
			||||||
import { t } from "../services/i18n.js";
 | 
					import { t } from "../services/i18n.js";
 | 
				
			||||||
@@ -106,7 +106,7 @@ async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HT
 | 
				
			|||||||
            await linkService.loadReferenceLinkTitle($(el));
 | 
					            await linkService.loadReferenceLinkTitle($(el));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await applySyntaxHighlight($renderedContent);
 | 
					        await formatCodeBlocks($renderedContent);
 | 
				
			||||||
    } else if (note instanceof FNote) {
 | 
					    } else if (note instanceof FNote) {
 | 
				
			||||||
        await renderChildrenList($renderedContent, note);
 | 
					        await renderChildrenList($renderedContent, note);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
import type FNote from "../entities/fnote.js";
 | 
					import type FNote from "../entities/fnote.js";
 | 
				
			||||||
import { getCurrentLanguage } from "./i18n.js";
 | 
					import { getCurrentLanguage } from "./i18n.js";
 | 
				
			||||||
import { applySyntaxHighlight } from "./syntax_highlight.js";
 | 
					import { formatCodeBlocks } from "./syntax_highlight.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function renderDoc(note: FNote) {
 | 
					export default function renderDoc(note: FNote) {
 | 
				
			||||||
    return new Promise<JQuery<HTMLElement>>((resolve) => {
 | 
					    return new Promise<JQuery<HTMLElement>>((resolve) => {
 | 
				
			||||||
@@ -41,7 +41,7 @@ function processContent(url: string, $content: JQuery<HTMLElement>) {
 | 
				
			|||||||
        $img.attr("src", dir + "/" + $img.attr("src"));
 | 
					        $img.attr("src", dir + "/" + $img.attr("src"));
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    applySyntaxHighlight($content);
 | 
					    formatCodeBlocks($content);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function getUrl(docNameValue: string, language: string) {
 | 
					function getUrl(docNameValue: string, language: string) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,15 +6,15 @@ let highlightingLoaded = false;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Identifies all the code blocks (as `pre code`) under the specified hierarchy and uses the highlight.js library to obtain the highlighted text which is then applied on to the code blocks.
 | 
					 * Identifies all the code blocks (as `pre code`) under the specified hierarchy and uses the highlight.js library to obtain the highlighted text which is then applied on to the code blocks.
 | 
				
			||||||
 | 
					 * Additionally, adds a "Copy to clipboard" button.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param $container the container under which to look for code blocks and to apply syntax highlighting to them.
 | 
					 * @param $container the container under which to look for code blocks and to apply syntax highlighting to them.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export async function applySyntaxHighlight($container: JQuery<HTMLElement>) {
 | 
					export async function formatCodeBlocks($container: JQuery<HTMLElement>) {
 | 
				
			||||||
    if (!isSyntaxHighlightEnabled()) {
 | 
					    const syntaxHighlightingEnabled = isSyntaxHighlightEnabled();
 | 
				
			||||||
        return;
 | 
					    if (syntaxHighlightingEnabled) {
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        await ensureMimeTypesForHighlighting();
 | 
					        await ensureMimeTypesForHighlighting();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const codeBlocks = $container.find("pre code");
 | 
					    const codeBlocks = $container.find("pre code");
 | 
				
			||||||
    for (const codeBlock of codeBlocks) {
 | 
					    for (const codeBlock of codeBlocks) {
 | 
				
			||||||
@@ -23,8 +23,18 @@ export async function applySyntaxHighlight($container: JQuery<HTMLElement>) {
 | 
				
			|||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        applyCopyToClipboardButton($(codeBlock));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (syntaxHighlightingEnabled) {
 | 
				
			||||||
            applySingleBlockSyntaxHighlight($(codeBlock), normalizedMimeType);
 | 
					            applySingleBlockSyntaxHighlight($(codeBlock), normalizedMimeType);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export function applyCopyToClipboardButton($codeBlock: JQuery<HTMLElement>) {
 | 
				
			||||||
 | 
					    const $copyButton = $("<button>")
 | 
				
			||||||
 | 
					        .addClass("bx component btn tn-tool-button bx-copy copy-button");
 | 
				
			||||||
 | 
					    $codeBlock.parent().append($copyButton);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -529,6 +529,26 @@ pre:not(.hljs) {
 | 
				
			|||||||
    font-size: 100%;
 | 
					    font-size: 100%;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pre {
 | 
				
			||||||
 | 
					    position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pre > button.copy-button {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 1em;
 | 
				
			||||||
 | 
					    right: 1em;
 | 
				
			||||||
 | 
					    opacity: 0.8;    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pre > button.copy-button:hover {
 | 
				
			||||||
 | 
					    color: inherit !important;
 | 
				
			||||||
 | 
					    opacity: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pre > button.copy-button:active {
 | 
				
			||||||
 | 
					    background-color: unset !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.pointer {
 | 
					.pointer {
 | 
				
			||||||
    cursor: pointer;
 | 
					    cursor: pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,7 +12,7 @@ import { createChatSession, checkSessionExists, setupStreamingResponse, getDirec
 | 
				
			|||||||
import { extractInChatToolSteps } from "./message_processor.js";
 | 
					import { extractInChatToolSteps } from "./message_processor.js";
 | 
				
			||||||
import { validateEmbeddingProviders } from "./validation.js";
 | 
					import { validateEmbeddingProviders } from "./validation.js";
 | 
				
			||||||
import type { MessageData, ToolExecutionStep, ChatData } from "./types.js";
 | 
					import type { MessageData, ToolExecutionStep, ChatData } from "./types.js";
 | 
				
			||||||
import { applySyntaxHighlight } from "../../services/syntax_highlight.js";
 | 
					import { formatCodeBlocks } from "../../services/syntax_highlight.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "../../stylesheets/llm_chat.css";
 | 
					import "../../stylesheets/llm_chat.css";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -925,7 +925,7 @@ export default class LlmChatPanel extends BasicWidget {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        // Apply syntax highlighting if this is the final update
 | 
					        // Apply syntax highlighting if this is the final update
 | 
				
			||||||
        if (isDone) {
 | 
					        if (isDone) {
 | 
				
			||||||
            applySyntaxHighlight($(assistantMessageEl as HTMLElement));
 | 
					            formatCodeBlocks($(assistantMessageEl as HTMLElement));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Update message in the data model for storage
 | 
					            // Update message in the data model for storage
 | 
				
			||||||
            // Find the last assistant message to update, or add a new one if none exists
 | 
					            // Find the last assistant message to update, or add a new one if none exists
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,7 +2,7 @@
 | 
				
			|||||||
 * Utility functions for LLM Chat
 | 
					 * Utility functions for LLM Chat
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
import { marked } from "marked";
 | 
					import { marked } from "marked";
 | 
				
			||||||
import { applySyntaxHighlight } from "../../services/syntax_highlight.js";
 | 
					import { formatCodeBlocks } from "../../services/syntax_highlight.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Format markdown content for display
 | 
					 * Format markdown content for display
 | 
				
			||||||
@@ -62,7 +62,7 @@ export function escapeHtml(text: string): string {
 | 
				
			|||||||
 * Apply syntax highlighting to content
 | 
					 * Apply syntax highlighting to content
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function applyHighlighting(element: HTMLElement): void {
 | 
					export function applyHighlighting(element: HTMLElement): void {
 | 
				
			||||||
    applySyntaxHighlight($(element));
 | 
					    formatCodeBlocks($(element));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
 | 
					import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
 | 
				
			||||||
import { applySyntaxHighlight } from "../../services/syntax_highlight.js";
 | 
					import { formatCodeBlocks } from "../../services/syntax_highlight.js";
 | 
				
			||||||
import type FNote from "../../entities/fnote.js";
 | 
					import type FNote from "../../entities/fnote.js";
 | 
				
			||||||
import type { CommandListenerData, EventData } from "../../components/app_context.js";
 | 
					import type { CommandListenerData, EventData } from "../../components/app_context.js";
 | 
				
			||||||
import { getLocaleById } from "../../services/i18n.js";
 | 
					import { getLocaleById } from "../../services/i18n.js";
 | 
				
			||||||
@@ -125,7 +125,7 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        await this.#applyInlineMermaid();
 | 
					        await this.#applyInlineMermaid();
 | 
				
			||||||
        await applySyntaxHighlight(this.$content);
 | 
					        await formatCodeBlocks(this.$content);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async #applyInlineMermaid() {
 | 
					    async #applyInlineMermaid() {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user