mirror of
https://github.com/zadam/trilium.git
synced 2025-11-18 03:00:41 +01:00
Compare commits
10 Commits
feat/ui/no
...
siriusbcd_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
529f9a2fb9 | ||
|
|
6b0bcf93d3 | ||
|
|
13afe33244 | ||
|
|
64a756cc04 | ||
|
|
f57e90b35c | ||
|
|
5a5d242ea0 | ||
|
|
4afea27fa5 | ||
|
|
be19d1f5b5 | ||
|
|
a22687e2d8 | ||
|
|
44475853df |
@@ -647,7 +647,32 @@ export default class TabManager extends Component {
|
||||
...this.noteContexts.slice(-noteContexts.length),
|
||||
...this.noteContexts.slice(lastClosedTab.position, -noteContexts.length)
|
||||
];
|
||||
this.noteContextReorderEvent({ ntxIdsInOrder: ntxsInOrder.map((nc) => nc.ntxId).filter((id) => id !== null) });
|
||||
|
||||
// Update mainNtxId if the restored pane is the main pane in the split pane
|
||||
const { oldMainNtxId, newMainNtxId } = (() => {
|
||||
if (noteContexts.length !== 1) {
|
||||
return { oldMainNtxId: undefined, newMainNtxId: undefined };
|
||||
}
|
||||
|
||||
const mainNtxId = noteContexts[0]?.mainNtxId;
|
||||
const index = this.noteContexts.findIndex(c => c.ntxId === mainNtxId);
|
||||
|
||||
// No need to update if the restored position is after mainNtxId
|
||||
if (index === -1 || lastClosedTab.position > index) {
|
||||
return { oldMainNtxId: undefined, newMainNtxId: undefined };
|
||||
}
|
||||
|
||||
return {
|
||||
oldMainNtxId: this.noteContexts[index].ntxId ?? undefined,
|
||||
newMainNtxId: noteContexts[0]?.ntxId ?? undefined
|
||||
};
|
||||
})();
|
||||
|
||||
this.triggerCommand("noteContextReorder", {
|
||||
ntxIdsInOrder: ntxsInOrder.map((nc) => nc.ntxId).filter((id) => id !== null),
|
||||
oldMainNtxId,
|
||||
newMainNtxId
|
||||
});
|
||||
|
||||
let mainNtx = noteContexts.find((nc) => nc.isMainContext());
|
||||
if (mainNtx) {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { KeyboardActionNames } from "@triliumnext/commons";
|
||||
import keyboardActionService, { getActionSync } from "../services/keyboard_actions.js";
|
||||
import note_tooltip from "../services/note_tooltip.js";
|
||||
import utils from "../services/utils.js";
|
||||
import { h, JSX, render } from "preact";
|
||||
import { should } from "vitest";
|
||||
|
||||
export interface ContextMenuOptions<T> {
|
||||
x: number;
|
||||
@@ -15,11 +15,6 @@ export interface ContextMenuOptions<T> {
|
||||
onHide?: () => void;
|
||||
}
|
||||
|
||||
export interface CustomMenuItem {
|
||||
kind: "custom",
|
||||
componentFn: () => JSX.Element | null;
|
||||
}
|
||||
|
||||
export interface MenuSeparatorItem {
|
||||
kind: "separator";
|
||||
}
|
||||
@@ -56,7 +51,7 @@ export interface MenuCommandItem<T> {
|
||||
columns?: number;
|
||||
}
|
||||
|
||||
export type MenuItem<T> = MenuCommandItem<T> | CustomMenuItem | MenuSeparatorItem | MenuHeader;
|
||||
export type MenuItem<T> = MenuCommandItem<T> | MenuSeparatorItem | MenuHeader;
|
||||
export type MenuHandler<T> = (item: MenuCommandItem<T>, e: JQuery.MouseDownEvent<HTMLElement, undefined, HTMLElement, HTMLElement>) => void;
|
||||
export type ContextMenuEvent = PointerEvent | MouseEvent | JQuery.ContextMenuEvent;
|
||||
|
||||
@@ -207,14 +202,118 @@ class ContextMenu {
|
||||
$group.append($("<h6>").addClass("dropdown-header").text(item.title));
|
||||
shouldResetGroup = true;
|
||||
} else {
|
||||
if ("kind" in item && item.kind === "custom") {
|
||||
// Custom menu item
|
||||
$group.append(this.createCustomMenuItem(item));
|
||||
} else {
|
||||
// Standard menu item
|
||||
$group.append(this.createMenuItem(item));
|
||||
const $icon = $("<span>");
|
||||
|
||||
if ("uiIcon" in item || "checked" in item) {
|
||||
const icon = (item.checked ? "bx bx-check" : item.uiIcon);
|
||||
if (icon) {
|
||||
$icon.addClass(icon);
|
||||
} else {
|
||||
$icon.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
const $link = $("<span>")
|
||||
.append($icon)
|
||||
.append(" ") // some space between icon and text
|
||||
.append(item.title);
|
||||
|
||||
if ("badges" in item && item.badges) {
|
||||
for (let badge of item.badges) {
|
||||
const badgeElement = $(`<span class="badge">`).text(badge.title);
|
||||
|
||||
if (badge.className) {
|
||||
badgeElement.addClass(badge.className);
|
||||
}
|
||||
|
||||
$link.append(badgeElement);
|
||||
}
|
||||
}
|
||||
|
||||
if ("keyboardShortcut" in item && item.keyboardShortcut) {
|
||||
const shortcuts = getActionSync(item.keyboardShortcut).effectiveShortcuts;
|
||||
if (shortcuts) {
|
||||
const allShortcuts: string[] = [];
|
||||
for (const effectiveShortcut of shortcuts) {
|
||||
allShortcuts.push(effectiveShortcut.split("+")
|
||||
.map(key => `<kbd>${key}</kbd>`)
|
||||
.join("+"));
|
||||
}
|
||||
|
||||
if (allShortcuts.length) {
|
||||
const container = $("<span>").addClass("keyboard-shortcut");
|
||||
container.append($(allShortcuts.join(",")));
|
||||
$link.append(container);
|
||||
}
|
||||
}
|
||||
} else if ("shortcut" in item && item.shortcut) {
|
||||
$link.append($("<kbd>").text(item.shortcut));
|
||||
}
|
||||
|
||||
const $item = $("<li>")
|
||||
.addClass("dropdown-item")
|
||||
.append($link)
|
||||
.on("contextmenu", (e) => false)
|
||||
// important to use mousedown instead of click since the former does not change focus
|
||||
// (especially important for focused text for spell check)
|
||||
.on("mousedown", (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (e.which !== 1) {
|
||||
// only left click triggers menu items
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isMobile && "items" in item && item.items) {
|
||||
const $item = $(e.target).closest(".dropdown-item");
|
||||
|
||||
$item.toggleClass("submenu-open");
|
||||
$item.find("ul.dropdown-menu").toggleClass("show");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("handler" in item && item.handler) {
|
||||
item.handler(item, e);
|
||||
}
|
||||
|
||||
this.options?.selectMenuItemHandler(item, e);
|
||||
|
||||
// it's important to stop the propagation especially for sub-menus, otherwise the event
|
||||
// might be handled again by top-level menu
|
||||
return false;
|
||||
});
|
||||
|
||||
$item.on("mouseup", (e) => {
|
||||
// Prevent submenu from failing to expand on mobile
|
||||
if (!this.isMobile || !("items" in item && item.items)) {
|
||||
e.stopPropagation();
|
||||
// Hide the content menu on mouse up to prevent the mouse event from propagating to the elements below.
|
||||
this.hide();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if ("enabled" in item && item.enabled !== undefined && !item.enabled) {
|
||||
$item.addClass("disabled");
|
||||
}
|
||||
|
||||
if ("items" in item && item.items) {
|
||||
$item.addClass("dropdown-submenu");
|
||||
$link.addClass("dropdown-toggle");
|
||||
|
||||
const $subMenu = $("<ul>").addClass("dropdown-menu");
|
||||
const hasColumns = !!item.columns && item.columns > 1;
|
||||
if (!this.isMobile && hasColumns) {
|
||||
$subMenu.css("column-count", item.columns!);
|
||||
}
|
||||
|
||||
this.addItems($subMenu, item.items, hasColumns);
|
||||
|
||||
$item.append($subMenu);
|
||||
}
|
||||
|
||||
$group.append($item);
|
||||
|
||||
// After adding a menu item, if the previous item was a separator or header,
|
||||
// reset the group so that the next item will be appended directly to the parent.
|
||||
if (shouldResetGroup) {
|
||||
@@ -225,126 +324,6 @@ class ContextMenu {
|
||||
}
|
||||
}
|
||||
|
||||
private createCustomMenuItem(item: CustomMenuItem) {
|
||||
const element = document.createElement("li");
|
||||
element.classList.add("dropdown-custom-item");
|
||||
render(h(item.componentFn, {}), element);
|
||||
return element;
|
||||
}
|
||||
|
||||
private createMenuItem(item: MenuCommandItem<any>) {
|
||||
const $icon = $("<span>");
|
||||
|
||||
if ("uiIcon" in item || "checked" in item) {
|
||||
const icon = (item.checked ? "bx bx-check" : item.uiIcon);
|
||||
if (icon) {
|
||||
$icon.addClass(icon);
|
||||
} else {
|
||||
$icon.append(" ");
|
||||
}
|
||||
}
|
||||
|
||||
const $link = $("<span>")
|
||||
.append($icon)
|
||||
.append(" ") // some space between icon and text
|
||||
.append(item.title);
|
||||
|
||||
if ("badges" in item && item.badges) {
|
||||
for (let badge of item.badges) {
|
||||
const badgeElement = $(`<span class="badge">`).text(badge.title);
|
||||
|
||||
if (badge.className) {
|
||||
badgeElement.addClass(badge.className);
|
||||
}
|
||||
|
||||
$link.append(badgeElement);
|
||||
}
|
||||
}
|
||||
|
||||
if ("keyboardShortcut" in item && item.keyboardShortcut) {
|
||||
const shortcuts = getActionSync(item.keyboardShortcut).effectiveShortcuts;
|
||||
if (shortcuts) {
|
||||
const allShortcuts: string[] = [];
|
||||
for (const effectiveShortcut of shortcuts) {
|
||||
allShortcuts.push(effectiveShortcut.split("+")
|
||||
.map(key => `<kbd>${key}</kbd>`)
|
||||
.join("+"));
|
||||
}
|
||||
|
||||
if (allShortcuts.length) {
|
||||
const container = $("<span>").addClass("keyboard-shortcut");
|
||||
container.append($(allShortcuts.join(",")));
|
||||
$link.append(container);
|
||||
}
|
||||
}
|
||||
} else if ("shortcut" in item && item.shortcut) {
|
||||
$link.append($("<kbd>").text(item.shortcut));
|
||||
}
|
||||
|
||||
const $item = $("<li>")
|
||||
.addClass("dropdown-item")
|
||||
.append($link)
|
||||
.on("contextmenu", (e) => false)
|
||||
// important to use mousedown instead of click since the former does not change focus
|
||||
// (especially important for focused text for spell check)
|
||||
.on("mousedown", (e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
if (e.which !== 1) {
|
||||
// only left click triggers menu items
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.isMobile && "items" in item && item.items) {
|
||||
const $item = $(e.target).closest(".dropdown-item");
|
||||
|
||||
$item.toggleClass("submenu-open");
|
||||
$item.find("ul.dropdown-menu").toggleClass("show");
|
||||
return false;
|
||||
}
|
||||
|
||||
if ("handler" in item && item.handler) {
|
||||
item.handler(item, e);
|
||||
}
|
||||
|
||||
this.options?.selectMenuItemHandler(item, e);
|
||||
|
||||
// it's important to stop the propagation especially for sub-menus, otherwise the event
|
||||
// might be handled again by top-level menu
|
||||
return false;
|
||||
});
|
||||
|
||||
$item.on("mouseup", (e) => {
|
||||
// Prevent submenu from failing to expand on mobile
|
||||
if (!this.isMobile || !("items" in item && item.items)) {
|
||||
e.stopPropagation();
|
||||
// Hide the content menu on mouse up to prevent the mouse event from propagating to the elements below.
|
||||
this.hide();
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
if ("enabled" in item && item.enabled !== undefined && !item.enabled) {
|
||||
$item.addClass("disabled");
|
||||
}
|
||||
|
||||
if ("items" in item && item.items) {
|
||||
$item.addClass("dropdown-submenu");
|
||||
$link.addClass("dropdown-toggle");
|
||||
|
||||
const $subMenu = $("<ul>").addClass("dropdown-menu");
|
||||
const hasColumns = !!item.columns && item.columns > 1;
|
||||
if (!this.isMobile && hasColumns) {
|
||||
$subMenu.css("column-count", item.columns!);
|
||||
}
|
||||
|
||||
this.addItems($subMenu, item.items, hasColumns);
|
||||
|
||||
$item.append($subMenu);
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
|
||||
async hide() {
|
||||
this.options?.onHide?.();
|
||||
this.$widget.removeClass("show");
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
.color-picker-menu-item {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.color-picker-menu-item > .color-cell {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.color-picker-menu-item > .color-cell.disabled-color-cell {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.color-picker-menu-item > .color-cell.selected {
|
||||
outline: 2px solid royalblue;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import "./NoteColorPickerMenuItem.css";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import attributes from "../../services/attributes";
|
||||
import FNote from "../../entities/fnote";
|
||||
import froca from "../../services/froca";
|
||||
|
||||
const COLORS = ["blue", "green", "cyan", "red", "magenta", "brown", "yellow", ""];
|
||||
|
||||
export interface NoteColorPickerMenuItemProps {
|
||||
/** The target Note instance or its ID string. */
|
||||
note: FNote | string | null;
|
||||
}
|
||||
|
||||
export default function NoteColorPickerMenuItem(props: NoteColorPickerMenuItemProps) {
|
||||
if (!props.note) return null;
|
||||
|
||||
const [note, setNote] = useState<FNote | null>(null);
|
||||
const [currentColor, setCurrentColor] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const retrieveNote = async (noteId: string) => {
|
||||
const result = await froca.getNote(noteId, true);
|
||||
if (result) {
|
||||
setNote(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof props.note === "string") {
|
||||
retrieveNote(props.note); // Get the note from the given ID string
|
||||
} else {
|
||||
setNote(props.note);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setCurrentColor(note?.getLabel("color")?.value ?? "");
|
||||
}, [note]);
|
||||
|
||||
const onColorCellClicked = (color: string) => {
|
||||
if (note) {
|
||||
attributes.setLabel(note.noteId, "color", color);
|
||||
setCurrentColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
return <div className="color-picker-menu-item">
|
||||
{COLORS.map((color) => (
|
||||
<ColorCell key={color}
|
||||
color={color}
|
||||
isSelected={(color === currentColor)}
|
||||
isDisabled={(note === null)}
|
||||
onClick={() => onColorCellClicked(color)} />
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
|
||||
interface ColorCellProps {
|
||||
color: string,
|
||||
isSelected: boolean,
|
||||
isDisabled?: boolean,
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
function ColorCell(props: ColorCellProps) {
|
||||
return <div class={`color-cell ${props.isSelected ? "selected" : ""} ${props.isDisabled ? "disabled-color-cell" : ""}`}
|
||||
style={`background-color: ${props.color}`}
|
||||
onClick={props.onClick}>
|
||||
</div>;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
import NoteColorPickerMenuItem from "./custom-items/NoteColorPickerMenuItem.jsx";
|
||||
import treeService from "../services/tree.js";
|
||||
import froca from "../services/froca.js";
|
||||
import clipboard from "../services/clipboard.js";
|
||||
@@ -256,20 +255,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
|
||||
keyboardShortcut: "searchInSubtree",
|
||||
uiIcon: "bx bx-search",
|
||||
enabled: notSearch && noSelectedNotes
|
||||
},
|
||||
|
||||
{ kind: "separator"},
|
||||
|
||||
{
|
||||
kind: "custom",
|
||||
componentFn: () => {
|
||||
if (notOptionsOrHelp && selectedNotes.length === 1) {
|
||||
return NoteColorPickerMenuItem({note});
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
];
|
||||
return items.filter((row) => row !== null) as MenuItem<TreeCommandNames>[];
|
||||
}
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { t } from "../../services/i18n";
|
||||
import ActionButton from "../react/ActionButton";
|
||||
import { useNoteContext, useTriliumEvent } from "../react/hooks";
|
||||
import { useNoteContext, useTriliumEvents } from "../react/hooks";
|
||||
import appContext from "../../components/app_context";
|
||||
|
||||
export default function ClosePaneButton() {
|
||||
const { noteContext, ntxId, parentComponent } = useNoteContext();
|
||||
const [ isEnabled, setIsEnabled ] = useState(false);
|
||||
const [isEnabled, setIsEnabled] = useState(false);
|
||||
|
||||
function refresh() {
|
||||
setIsEnabled(!!(noteContext && !!noteContext.mainNtxId));
|
||||
const isMainOfSomeContext = appContext.tabManager.noteContexts.some(c => c.mainNtxId === ntxId);
|
||||
setIsEnabled(!!(noteContext && (!!noteContext.mainNtxId || isMainOfSomeContext)));
|
||||
}
|
||||
|
||||
useTriliumEvent("noteContextReorder", refresh);
|
||||
useEffect(refresh, [ ntxId ]);
|
||||
useTriliumEvents(["noteContextRemoved", "noteContextReorder", "newNoteContextCreated"], refresh);
|
||||
useEffect(refresh, [ntxId]);
|
||||
|
||||
return (
|
||||
<ActionButton
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import FNote from "../../../entities/fnote";
|
||||
import NoteColorPickerMenuItem from "../../../menus/custom-items/NoteColorPickerMenuItem";
|
||||
import contextMenu, { ContextMenuEvent } from "../../../menus/context_menu";
|
||||
import link_context_menu from "../../../menus/link_context_menu";
|
||||
import attributes from "../../../services/attributes";
|
||||
@@ -75,11 +74,6 @@ export function openNoteContextMenu(api: Api, event: ContextMenuEvent, note: FNo
|
||||
uiIcon: "bx bx-trash",
|
||||
handler: () => branches.deleteNotes([ branchId ], false, false)
|
||||
},
|
||||
{ kind: "separator" },
|
||||
{
|
||||
kind: "custom",
|
||||
componentFn: () => NoteColorPickerMenuItem({note})
|
||||
}
|
||||
],
|
||||
selectMenuItemHandler: ({ command }) => link_context_menu.handleLinkContextMenuItem(command, note.noteId),
|
||||
});
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import NoteColorPickerMenuItem from "../../../menus/custom-items/NoteColorPickerMenuItem";
|
||||
import FNote from "../../../entities/fnote";
|
||||
import contextMenu, { ContextMenuEvent } from "../../../menus/context_menu";
|
||||
import link_context_menu from "../../../menus/link_context_menu";
|
||||
import branches from "../../../services/branches";
|
||||
import froca from "../../../services/froca";
|
||||
import { note } from "mermaid/dist/rendering-util/rendering-elements/shapes/note.js";
|
||||
import { t } from "../../../services/i18n";
|
||||
|
||||
export function openCalendarContextMenu(e: ContextMenuEvent, noteId: string, parentNote: FNote) {
|
||||
@@ -36,11 +34,6 @@ export function openCalendarContextMenu(e: ContextMenuEvent, noteId: string, par
|
||||
await branches.deleteNotes([ branchIdToDelete ], false, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
{ kind: "separator" },
|
||||
{
|
||||
kind: "custom",
|
||||
componentFn: () => NoteColorPickerMenuItem({note: noteId})
|
||||
}
|
||||
],
|
||||
selectMenuItemHandler: ({ command }) => link_context_menu.handleLinkContextMenuItem(command, noteId),
|
||||
|
||||
@@ -2,7 +2,6 @@ import type { LatLng, LeafletMouseEvent } from "leaflet";
|
||||
import appContext, { type CommandMappings } from "../../../components/app_context.js";
|
||||
import contextMenu, { type MenuItem } from "../../../menus/context_menu.js";
|
||||
import linkContextMenu from "../../../menus/link_context_menu.js";
|
||||
import NoteColorPickerMenuItem from "../../../menus/custom-items/NoteColorPickerMenuItem.jsx";
|
||||
import { t } from "../../../services/i18n.js";
|
||||
import { createNewNote } from "./api.js";
|
||||
import { copyTextWithToast } from "../../../services/clipboard_ext.js";
|
||||
@@ -19,12 +18,7 @@ export default function openContextMenu(noteId: string, e: LeafletMouseEvent, is
|
||||
items = [
|
||||
...items,
|
||||
{ kind: "separator" },
|
||||
{ title: t("geo-map-context.remove-from-map"), command: "deleteFromMap", uiIcon: "bx bx-trash" },
|
||||
{ kind: "separator"},
|
||||
{
|
||||
kind: "custom",
|
||||
componentFn: () => NoteColorPickerMenuItem({note: noteId})
|
||||
}
|
||||
{ title: t("geo-map-context.remove-from-map"), command: "deleteFromMap", uiIcon: "bx bx-trash" }
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import link_context_menu from "../../../menus/link_context_menu.js";
|
||||
import froca from "../../../services/froca.js";
|
||||
import branches from "../../../services/branches.js";
|
||||
import Component from "../../../components/component.js";
|
||||
import NoteColorPickerMenuItem from "../../../menus/custom-items/NoteColorPickerMenuItem.jsx";
|
||||
import { RefObject } from "preact";
|
||||
|
||||
export function useContextMenu(parentNote: FNote, parentComponent: Component | null | undefined, tabulator: RefObject<Tabulator>): Partial<EventCallBackMethods> {
|
||||
@@ -220,11 +219,6 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
|
||||
title: t("table_context_menu.delete_row"),
|
||||
uiIcon: "bx bx-trash",
|
||||
handler: () => branches.deleteNotes([ rowData.branchId ], false, false)
|
||||
},
|
||||
{ kind: "separator"},
|
||||
{
|
||||
kind: "custom",
|
||||
componentFn: () => NoteColorPickerMenuItem({note: rowData.noteId})
|
||||
}
|
||||
],
|
||||
selectMenuItemHandler: ({ command }) => link_context_menu.handleLinkContextMenuItem(command, rowData.noteId),
|
||||
|
||||
@@ -100,9 +100,22 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
|
||||
}
|
||||
|
||||
async closeThisNoteSplitCommand({ ntxId }: CommandListenerData<"closeThisNoteSplit">) {
|
||||
if (ntxId) {
|
||||
await appContext.tabManager.removeNoteContext(ntxId);
|
||||
if (!ntxId) return;
|
||||
const contexts = appContext.tabManager.noteContexts;
|
||||
const currentIndex = contexts.findIndex((c) => c.ntxId === ntxId);
|
||||
if (currentIndex === -1) return;
|
||||
|
||||
const isRemoveMainContext = contexts[currentIndex].isMainContext();
|
||||
if (isRemoveMainContext && currentIndex + 1 < contexts.length) {
|
||||
const ntxIds = contexts.map((c) => c.ntxId).filter((c) => !!c) as string[];
|
||||
this.triggerCommand("noteContextReorder", {
|
||||
ntxIdsInOrder: ntxIds,
|
||||
oldMainNtxId: ntxId,
|
||||
newMainNtxId: ntxIds[currentIndex + 1]
|
||||
});
|
||||
}
|
||||
|
||||
await appContext.tabManager.removeNoteContext(ntxId);
|
||||
}
|
||||
|
||||
async moveThisNoteSplitCommand({ ntxId, isMovingLeft }: CommandListenerData<"moveThisNoteSplit">) {
|
||||
@@ -167,12 +180,16 @@ export default class SplitNoteContainer extends FlexContainer<SplitNoteWidget> {
|
||||
splitService.delNoteSplitResizer(ntxIds);
|
||||
}
|
||||
|
||||
contextsReopenedEvent({ ntxId, afterNtxId }: EventData<"contextsReopened">) {
|
||||
if (ntxId === undefined || afterNtxId === undefined) {
|
||||
// no single split reopened
|
||||
return;
|
||||
contextsReopenedEvent({ ntxId, mainNtxId, afterNtxId }: EventData<"contextsReopened">) {
|
||||
if (ntxId !== undefined && afterNtxId !== undefined) {
|
||||
this.$widget.find(`[data-ntx-id="${ntxId}"]`).insertAfter(this.$widget.find(`[data-ntx-id="${afterNtxId}"]`));
|
||||
} else if (mainNtxId) {
|
||||
const contexts = appContext.tabManager.noteContexts;
|
||||
const nextIndex = contexts.findIndex(c => c.ntxId === mainNtxId);
|
||||
const beforeNtxId = (nextIndex !== -1 && nextIndex + 1 < contexts.length) ? contexts[nextIndex + 1].ntxId : null;
|
||||
|
||||
this.$widget.find(`[data-ntx-id="${mainNtxId}"]`).insertBefore(this.$widget.find(`[data-ntx-id="${beforeNtxId}"]`));
|
||||
}
|
||||
this.$widget.find(`[data-ntx-id="${ntxId}"]`).insertAfter(this.$widget.find(`[data-ntx-id="${afterNtxId}"]`));
|
||||
}
|
||||
|
||||
async refresh() {
|
||||
|
||||
@@ -820,12 +820,15 @@ export default class TabRowWidget extends BasicWidget {
|
||||
}
|
||||
|
||||
contextsReopenedEvent({ mainNtxId, tabPosition }: EventData<"contextsReopened">) {
|
||||
if (!mainNtxId || !tabPosition) {
|
||||
if (!mainNtxId || tabPosition < 0) {
|
||||
// no tab reopened
|
||||
return;
|
||||
}
|
||||
const tabEl = this.getTabById(mainNtxId)[0];
|
||||
tabEl.parentNode?.insertBefore(tabEl, this.tabEls[tabPosition]);
|
||||
|
||||
if ( tabEl && tabEl.parentNode ){
|
||||
tabEl.parentNode.insertBefore(tabEl, this.tabEls[tabPosition]);
|
||||
}
|
||||
}
|
||||
|
||||
updateTabById(ntxId: string | null) {
|
||||
|
||||
@@ -325,6 +325,11 @@ function renderText(result: Result, note: SNote | BNote) {
|
||||
|
||||
// Apply syntax highlight.
|
||||
for (const codeEl of document.querySelectorAll("pre code")) {
|
||||
if (codeEl.classList.contains("language-mermaid") && note.type === "text") {
|
||||
// Mermaid is handled on client-side, we don't want to break it by adding syntax highlighting.
|
||||
continue;
|
||||
}
|
||||
|
||||
const highlightResult = highlightAuto(codeEl.innerText);
|
||||
codeEl.innerHTML = highlightResult.value;
|
||||
codeEl.classList.add("hljs");
|
||||
|
||||
Reference in New Issue
Block a user