mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	feat(share): enable syntax highlighting
This commit is contained in:
		@@ -109,39 +109,6 @@ function isClipboardEmpty() {
 | 
			
		||||
    return clipboardBranchIds.length === 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function copyText(text: string) {
 | 
			
		||||
    if (!text) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let succeeded = false;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
        if (navigator.clipboard) {
 | 
			
		||||
            navigator.clipboard.writeText(text);
 | 
			
		||||
            succeeded = true;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Fallback method: https://stackoverflow.com/a/72239825
 | 
			
		||||
            const textArea = document.createElement("textarea");
 | 
			
		||||
            textArea.value = text;
 | 
			
		||||
            document.body.appendChild(textArea);
 | 
			
		||||
            textArea.focus();
 | 
			
		||||
            textArea.select();
 | 
			
		||||
            succeeded = document.execCommand('copy');
 | 
			
		||||
            document.body.removeChild(textArea);
 | 
			
		||||
        }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        console.warn(e);
 | 
			
		||||
        succeeded = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (succeeded) {
 | 
			
		||||
        toast.showMessage(t("clipboard.copy_success"));
 | 
			
		||||
    } else {
 | 
			
		||||
        toast.showError(t("clipboard.copy_failed"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
    pasteAfter,
 | 
			
		||||
    pasteInto,
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										37
									
								
								apps/client/src/services/clipboard_ext.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								apps/client/src/services/clipboard_ext.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
export function copyText(text: string) {
 | 
			
		||||
    if (!text) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    try {
 | 
			
		||||
        if (navigator.clipboard) {
 | 
			
		||||
            navigator.clipboard.writeText(text);
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            // Fallback method: https://stackoverflow.com/a/72239825
 | 
			
		||||
            const textArea = document.createElement("textarea");
 | 
			
		||||
            textArea.value = text;
 | 
			
		||||
            try {
 | 
			
		||||
                document.body.appendChild(textArea);
 | 
			
		||||
                textArea.focus();
 | 
			
		||||
                textArea.select();
 | 
			
		||||
                return document.execCommand('copy');
 | 
			
		||||
            } finally {
 | 
			
		||||
                document.body.removeChild(textArea);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
        console.warn(e);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function copyTextWithToast(text: string) {
 | 
			
		||||
    const t = (await import("./i18n.js")).t;
 | 
			
		||||
    const toast = (await import("./toast.js")).default;
 | 
			
		||||
 | 
			
		||||
    if (copyText(text)) {
 | 
			
		||||
        toast.showMessage(t("clipboard.copy_success"));
 | 
			
		||||
    } else {
 | 
			
		||||
        toast.showError(t("clipboard.copy_failed"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -1,4 +1,5 @@
 | 
			
		||||
import server from "./server.js";
 | 
			
		||||
import { isShare } from "./utils.js";
 | 
			
		||||
 | 
			
		||||
type OptionValue = number | string;
 | 
			
		||||
 | 
			
		||||
@@ -7,7 +8,9 @@ class Options {
 | 
			
		||||
    private arr!: Record<string, OptionValue>;
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        this.initializedPromise = server.get<Record<string, OptionValue>>("options").then((data) => this.load(data));
 | 
			
		||||
        if (!isShare) {
 | 
			
		||||
            this.initializedPromise = server.get<Record<string, OptionValue>>("options").then((data) => this.load(data));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    load(arr: Record<string, OptionValue>) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import utils from "./utils.js";
 | 
			
		||||
import utils, { isShare } from "./utils.js";
 | 
			
		||||
import ValidationError from "./validation_error.js";
 | 
			
		||||
 | 
			
		||||
type Headers = Record<string, string | null | undefined>;
 | 
			
		||||
@@ -28,6 +28,10 @@ export interface StandardResponse {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function getHeaders(headers?: Headers) {
 | 
			
		||||
    if (isShare) {
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const appContext = (await import("../components/app_context.js")).default;
 | 
			
		||||
    const activeNoteContext = appContext.tabManager ? appContext.tabManager.getActiveContext() : null;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@ import { ensureMimeTypes, highlight, highlightAuto, loadTheme, Themes, type Auto
 | 
			
		||||
import mime_types from "./mime_types.js";
 | 
			
		||||
import options from "./options.js";
 | 
			
		||||
import { t } from "./i18n.js";
 | 
			
		||||
import { copyText } from "./clipboard.js";
 | 
			
		||||
import { copyText } from "./clipboard_ext.js";
 | 
			
		||||
import { isShare } from "./utils.js";
 | 
			
		||||
import { MimeType } from "@triliumnext/commons";
 | 
			
		||||
 | 
			
		||||
let highlightingLoaded = false;
 | 
			
		||||
 | 
			
		||||
@@ -14,9 +16,6 @@ let highlightingLoaded = false;
 | 
			
		||||
 */
 | 
			
		||||
export async function formatCodeBlocks($container: JQuery<HTMLElement>) {
 | 
			
		||||
    const syntaxHighlightingEnabled = isSyntaxHighlightEnabled();
 | 
			
		||||
    if (syntaxHighlightingEnabled) {
 | 
			
		||||
        await ensureMimeTypesForHighlighting();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const codeBlocks = $container.find("pre code");
 | 
			
		||||
    for (const codeBlock of codeBlocks) {
 | 
			
		||||
@@ -49,11 +48,11 @@ export async function applySingleBlockSyntaxHighlight($codeBlock: JQuery<HTMLEle
 | 
			
		||||
    const text = $codeBlock.text();
 | 
			
		||||
 | 
			
		||||
    let highlightedText: HighlightResult | AutoHighlightResult | null = null;
 | 
			
		||||
    if (normalizedMimeType === mime_types.MIME_TYPE_AUTO) {
 | 
			
		||||
    if (normalizedMimeType === mime_types.MIME_TYPE_AUTO && !isShare) {
 | 
			
		||||
        await ensureMimeTypesForHighlighting();
 | 
			
		||||
        highlightedText = highlightAuto(text);
 | 
			
		||||
    } else if (normalizedMimeType) {
 | 
			
		||||
        await ensureMimeTypesForHighlighting();
 | 
			
		||||
        await ensureMimeTypesForHighlighting(normalizedMimeType);
 | 
			
		||||
        highlightedText = highlight(text, { language: normalizedMimeType });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -62,7 +61,7 @@ export async function applySingleBlockSyntaxHighlight($codeBlock: JQuery<HTMLEle
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export async function ensureMimeTypesForHighlighting() {
 | 
			
		||||
export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
 | 
			
		||||
    if (highlightingLoaded) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
@@ -72,7 +71,20 @@ export async function ensureMimeTypesForHighlighting() {
 | 
			
		||||
    loadHighlightingTheme(currentThemeName);
 | 
			
		||||
 | 
			
		||||
    // Load mime types.
 | 
			
		||||
    const mimeTypes = mime_types.getMimeTypes();
 | 
			
		||||
    let mimeTypes: MimeType[];
 | 
			
		||||
 | 
			
		||||
    if (mimeTypeHint) {
 | 
			
		||||
        mimeTypes = [
 | 
			
		||||
            {
 | 
			
		||||
                title: mimeTypeHint,
 | 
			
		||||
                enabled: true,
 | 
			
		||||
                mime: mimeTypeHint.replace("-", "/")
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    } else {
 | 
			
		||||
        mimeTypes = mime_types.getMimeTypes();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await ensureMimeTypes(mimeTypes);
 | 
			
		||||
 | 
			
		||||
    highlightingLoaded = true;
 | 
			
		||||
@@ -96,8 +108,12 @@ export function loadHighlightingTheme(themeName: string) {
 | 
			
		||||
 * @returns whether syntax highlighting should be enabled for code blocks.
 | 
			
		||||
 */
 | 
			
		||||
export function isSyntaxHighlightEnabled() {
 | 
			
		||||
    const theme = options.get("codeBlockTheme");
 | 
			
		||||
    return !!theme && theme !== "none";
 | 
			
		||||
    if (!isShare) {
 | 
			
		||||
        const theme = options.get("codeBlockTheme");
 | 
			
		||||
        return !!theme && theme !== "none";
 | 
			
		||||
    } else {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ import type { ViewScope } from "./link.js";
 | 
			
		||||
 | 
			
		||||
const SVG_MIME = "image/svg+xml";
 | 
			
		||||
 | 
			
		||||
export const isShare = !window.glob;
 | 
			
		||||
 | 
			
		||||
function reloadFrontendApp(reason?: string) {
 | 
			
		||||
    if (reason) {
 | 
			
		||||
        logInfo(`Frontend app reload: ${reason}`);
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,12 @@ import "@triliumnext/ckeditor5/content.css";
 | 
			
		||||
import "@triliumnext/share-theme/styles/index.css";
 | 
			
		||||
import "@triliumnext/share-theme/scripts/index.js";
 | 
			
		||||
 | 
			
		||||
import { formatCodeBlocks } from "./services/syntax_highlight.js";
 | 
			
		||||
import $ from "jquery";
 | 
			
		||||
 | 
			
		||||
window.$ = $;
 | 
			
		||||
formatCodeBlocks($("#content"));
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Fetch note with given ID from backend
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ import options from "../../../services/options.js";
 | 
			
		||||
import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js";
 | 
			
		||||
import utils from "../../../services/utils.js";
 | 
			
		||||
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?url";
 | 
			
		||||
import { copyText } from "../../../services/clipboard.js";
 | 
			
		||||
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
 | 
			
		||||
 | 
			
		||||
const TEXT_FORMATTING_GROUP = {
 | 
			
		||||
    label: "Text formatting",
 | 
			
		||||
@@ -116,7 +116,7 @@ export function buildConfig(): EditorConfig {
 | 
			
		||||
            enabled: isSyntaxHighlightEnabled()
 | 
			
		||||
        },
 | 
			
		||||
        clipboard: {
 | 
			
		||||
            copy: copyText
 | 
			
		||||
            copy: copyTextWithToast
 | 
			
		||||
        },
 | 
			
		||||
        // This value must be kept in sync with the language defined in webpack.config.js.
 | 
			
		||||
        language: "en"
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user