Merge branch 'develop' into open_in_new_window

This commit is contained in:
SiriusXT
2025-06-10 17:51:54 +08:00
65 changed files with 5040 additions and 263 deletions

View File

@@ -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,

View 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"));
}
}

View File

@@ -1,4 +1,5 @@
import server from "./server.js";
import { isShare } from "./utils.js";
type OptionValue = number | string;
@@ -7,7 +8,11 @@ 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));
} else {
this.initializedPromise = Promise.resolve();
}
}
load(arr: Record<string, OptionValue>) {

View File

@@ -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;

View File

@@ -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, copyTextWithToast } 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) {
@@ -37,7 +36,13 @@ export function applyCopyToClipboardButton($codeBlock: JQuery<HTMLElement>) {
const $copyButton = $("<button>")
.addClass("bx component icon-action tn-tool-button bx-copy copy-button")
.attr("title", t("code_block.copy_title"))
.on("click", () => copyText($codeBlock.text()));
.on("click", () => {
if (!isShare) {
copyTextWithToast($codeBlock.text());
} else {
copyText($codeBlock.text());
}
});
$codeBlock.parent().append($copyButton);
}
@@ -49,11 +54,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 +67,7 @@ export async function applySingleBlockSyntaxHighlight($codeBlock: JQuery<HTMLEle
}
}
export async function ensureMimeTypesForHighlighting() {
export async function ensureMimeTypesForHighlighting(mimeTypeHint?: string) {
if (highlightingLoaded) {
return;
}
@@ -72,7 +77,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 +114,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;
}
}
/**

View File

@@ -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}`);

View File

@@ -1,5 +1,33 @@
import "normalize.css";
import "boxicons/css/boxicons.min.css";
import "@triliumnext/ckeditor5/content.css";
import "@triliumnext/share-theme/styles/index.css";
import "@triliumnext/share-theme/scripts/index.js";
async function ensureJQuery() {
const $ = (await import("jquery")).default;
(window as any).$ = $;
}
async function applyMath() {
const anyMathBlock = document.querySelector("#content .math-tex");
if (!anyMathBlock) {
return;
}
const renderMathInElement = (await import("./services/math.js")).renderMathInElement;
renderMathInElement(document.getElementById("content"));
}
async function formatCodeBlocks() {
const anyCodeBlock = document.querySelector("#content pre");
if (!anyCodeBlock) {
return;
}
await ensureJQuery();
const { formatCodeBlocks } = await import("./services/syntax_highlight.js");
await formatCodeBlocks($("#content"));
}
/**
* Fetch note with given ID from backend
@@ -19,6 +47,9 @@ async function fetchNote(noteId: string | null = null) {
document.addEventListener(
"DOMContentLoaded",
() => {
formatCodeBlocks();
applyMath();
const toggleMenuButton = document.getElementById("toggleMenuButton");
const layout = document.getElementById("layout");

View File

@@ -1,223 +0,0 @@
body {
font-family: "Lucida Grande", "Lucida Sans Unicode", arial, sans-serif;
line-height: 1.5;
}
a {
text-decoration: none;
}
#layout {
max-width: 1200px;
margin: 0 auto;
display: flex;
flex-direction: row-reverse;
}
#menu {
padding: 25px;
flex-basis: 0;
flex-grow: 1;
overflow: auto;
}
#menu p {
margin: 0;
}
#menu > p {
font-weight: bold;
font-size: 110%;
}
#menu ul {
padding-left: 20px;
}
#main {
flex-basis: 0;
flex-grow: 3;
overflow: auto;
padding: 10px 20px 20px 20px;
}
#parentLink {
float: right;
margin-top: 20px;
}
#title {
margin: 0;
padding-top: 10px;
}
img {
max-width: 100%;
}
pre {
white-space: pre-wrap;
word-wrap: anywhere;
}
iframe.pdf-view {
width: 100%;
height: 800px;
}
#toggleMenuButton {
display: none;
position: fixed;
top: 8px;
left: 5px;
width: 1.4em;
border-radius: 5px;
border: 1px solid #aaa;
font-size: 2rem;
z-index: 10;
height: auto;
color: black;
cursor: pointer;
}
#childLinks.grid ul {
list-style-type: none;
display: flex;
flex-wrap: wrap;
padding: 0;
}
#childLinks.grid ul li {
width: 180px;
height: 140px;
padding: 10px;
}
#childLinks.grid ul li a {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
border: 1px solid #ddd;
border-radius: 5px;
justify-content: center;
align-content: center;
text-align: center;
font-size: large;
}
#childLinks.grid ul li a:hover {
background: #eee;
}
#childLinks.list ul {
list-style-type: none;
display: inline-flex;
flex-wrap: wrap;
padding: 0;
margin-top: 5px;
}
#childLinks.list ul li {
margin-right: 20px;
}
#noteClippedFrom {
padding: 10px 0 10px 0;
margin: 20px 0 20px 0;
color: #666;
border: 1px solid #ddd;
border-left: 0;
border-right: 0;
}
#toggleMenuButton::after {
position: relative;
top: -2px;
left: 1px;
}
@media (max-width: 48em) {
#layout.showMenu #menu {
display: block;
margin-top: 40px;
}
#toggleMenuButton {
display: block;
}
#layout.showMenu #main {
display: none;
}
#title {
padding-left: 60px;
}
#layout.showMenu #toggleMenuButton::after {
content: "«";
}
#toggleMenuButton::after {
content: "»";
}
#menu {
display: none;
}
}
.ck-content .footnote-section {
border-top: 1px solid #c4c4c4;
border-radius: 2px;
counter-reset: footnote-counter;
margin: 1em 0;
padding: 10px;
}
.ck-content .footnote-item {
counter-increment: footnote-counter;
display: flex;
list-style: none;
margin-left: 0.5em;
}
.ck-content .footnote-item:target .footnote-content {
background: #eee;
}
.ck-content .footnote-item > * {
vertical-align: text-top;
}
.ck-content .footnote-back-link {
margin-right: 0.1em;
position: relative;
top: -0.2em;
}
.ck-content .footnotes .footnote-back-link > sup {
margin-right: 0;
}
.ck-content .footnote-item:before {
content: counter(footnote-counter) ". ";
display: inline-block;
min-width: fit-content;
position: relative;
right: 0.2em;
text-align: right;
}
.ck-content .footnote-content {
border-radius: 2px;
display: inline-block;
flex-grow: 1;
padding: 0 0.3em;
width: 95%;
}
.ck-content .ck-content-widget.footnote-section .ck-content-widget__type-around__button_after {
display: none;
}

View File

@@ -7,3 +7,5 @@ declare module "@triliumnext/ckeditor5/emoji_definitions/en.json?url" {
var path: string;
export default path;
}
declare module "boxicons/css/boxicons.min.css" { }

View File

@@ -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"