mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00
Merge remote-tracking branch 'origin/develop' into feature/codemirror6
This commit is contained in:
commit
00a9908907
@ -60,7 +60,7 @@
|
|||||||
"@types/react": "19.1.3",
|
"@types/react": "19.1.3",
|
||||||
"@types/react-dom": "19.1.3",
|
"@types/react-dom": "19.1.3",
|
||||||
"copy-webpack-plugin": "13.0.0",
|
"copy-webpack-plugin": "13.0.0",
|
||||||
"happy-dom": "17.4.6",
|
"happy-dom": "17.4.7",
|
||||||
"script-loader": "0.7.2"
|
"script-loader": "0.7.2"
|
||||||
},
|
},
|
||||||
"nx": {
|
"nx": {
|
||||||
|
@ -277,10 +277,18 @@ export default class TabManager extends Component {
|
|||||||
return noteContext;
|
return noteContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
async openInNewTab(targetNoteId: string, hoistedNoteId: string | null = null) {
|
async openInNewTab(targetNoteId: string, hoistedNoteId: string | null = null, activate: boolean = false) {
|
||||||
const noteContext = await this.openEmptyTab(null, hoistedNoteId || this.getActiveContext()?.hoistedNoteId);
|
const noteContext = await this.openEmptyTab(null, hoistedNoteId || this.getActiveContext()?.hoistedNoteId);
|
||||||
|
|
||||||
await noteContext.setNote(targetNoteId);
|
await noteContext.setNote(targetNoteId);
|
||||||
|
|
||||||
|
if (activate && noteContext.notePath) {
|
||||||
|
this.activateNoteContext(noteContext.ntxId, false);
|
||||||
|
await this.triggerEvent("noteSwitchedAndActivated", {
|
||||||
|
noteContext,
|
||||||
|
notePath: noteContext.notePath
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openInSameTab(targetNoteId: string, hoistedNoteId: string | null = null) {
|
async openInSameTab(targetNoteId: string, hoistedNoteId: string | null = null) {
|
||||||
|
@ -126,7 +126,8 @@
|
|||||||
"collapseWholeTree": "collapse whole note tree",
|
"collapseWholeTree": "collapse whole note tree",
|
||||||
"collapseSubTree": "collapse sub-tree",
|
"collapseSubTree": "collapse sub-tree",
|
||||||
"tabShortcuts": "Tab shortcuts",
|
"tabShortcuts": "Tab shortcuts",
|
||||||
"newTabNoteLink": "<kbd>CTRL+click</kbd> - (or middle mouse click) on note link opens note in a new tab",
|
"newTabNoteLink": "<kbd>Ctrl+click</kbd> - (or <kbd>middle mouse click</kbd>) on note link opens note in a new tab",
|
||||||
|
"newTabWithActivationNoteLink": "<kbd>Ctrl+Shift+click</kbd> - (or <kbd>Shift+middle mouse click</kbd>) on note link opens and activates the note in a new tab",
|
||||||
"onlyInDesktop": "Only in desktop (Electron build)",
|
"onlyInDesktop": "Only in desktop (Electron build)",
|
||||||
"openEmptyTab": "open empty tab",
|
"openEmptyTab": "open empty tab",
|
||||||
"closeActiveTab": "close active tab",
|
"closeActiveTab": "close active tab",
|
||||||
|
@ -53,11 +53,12 @@ export default class NoteLauncher extends AbstractLauncher {
|
|||||||
await appContext.tabManager.openInSameTab(targetNoteId, hoistedNoteId);
|
await appContext.tabManager.openInSameTab(targetNoteId, hoistedNoteId);
|
||||||
} else {
|
} else {
|
||||||
const ctrlKey = utils.isCtrlKey(evt);
|
const ctrlKey = utils.isCtrlKey(evt);
|
||||||
|
const activate = evt.shiftKey ? true : false;
|
||||||
|
|
||||||
if ((evt.which === 1 && ctrlKey) || evt.which === 2) {
|
if ((evt.which === 1 && ctrlKey) || evt.which === 2) {
|
||||||
// TODO: Fix once tabManager is ported.
|
// TODO: Fix once tabManager is ported.
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
await appContext.tabManager.openInNewTab(targetNoteId, hoistedNoteId);
|
await appContext.tabManager.openInNewTab(targetNoteId, hoistedNoteId, activate);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Fix once tabManager is ported.
|
// TODO: Fix once tabManager is ported.
|
||||||
//@ts-ignore
|
//@ts-ignore
|
||||||
|
@ -28,15 +28,21 @@ export default class OpenNoteButtonWidget extends OnClickButtonWidget {
|
|||||||
if (evt.which === 3) {
|
if (evt.which === 3) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const hoistedNoteId = this.getHoistedNoteId();
|
||||||
const ctrlKey = utils.isCtrlKey(evt);
|
const ctrlKey = utils.isCtrlKey(evt);
|
||||||
|
|
||||||
if ((evt.which === 1 && ctrlKey) || evt.which === 2) {
|
if ((evt.which === 1 && ctrlKey) || evt.which === 2) {
|
||||||
await appContext.tabManager.openInNewTab(this.noteToOpen.noteId);
|
const activate = evt.shiftKey ? true : false;
|
||||||
|
await appContext.tabManager.openInNewTab(this.noteToOpen.noteId, hoistedNoteId, activate);
|
||||||
} else {
|
} else {
|
||||||
await appContext.tabManager.openInSameTab(this.noteToOpen.noteId);
|
await appContext.tabManager.openInSameTab(this.noteToOpen.noteId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getHoistedNoteId() {
|
||||||
|
return this.noteToOpen.getRelationValue("hoistedNote") || appContext.tabManager.getActiveContext()?.hoistedNoteId;
|
||||||
|
}
|
||||||
|
|
||||||
initialRenderCompleteEvent() {
|
initialRenderCompleteEvent() {
|
||||||
// we trigger refresh above
|
// we trigger refresh above
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ const TPL = /*html*/`
|
|||||||
<p class="card-text">
|
<p class="card-text">
|
||||||
<ul>
|
<ul>
|
||||||
<li>${t("help.newTabNoteLink")}</li>
|
<li>${t("help.newTabNoteLink")}</li>
|
||||||
|
<li>${t("help.newTabWithActivationNoteLink")}</li>
|
||||||
</ul>
|
</ul>
|
||||||
<h6>${t("help.onlyInDesktop")}:</h6>
|
<h6>${t("help.onlyInDesktop")}:</h6>
|
||||||
<ul>
|
<ul>
|
||||||
|
@ -230,7 +230,9 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
const notePath = treeService.getNotePath(node);
|
const notePath = treeService.getNotePath(node);
|
||||||
|
|
||||||
if (notePath) {
|
if (notePath) {
|
||||||
appContext.tabManager.openTabWithNoteWithHoisting(notePath);
|
appContext.tabManager.openTabWithNoteWithHoisting(notePath, {
|
||||||
|
activate: e.shiftKey ? true : false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
@ -343,11 +345,12 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
},
|
},
|
||||||
scrollParent: this.$tree,
|
scrollParent: this.$tree,
|
||||||
minExpandLevel: 2, // root can't be collapsed
|
minExpandLevel: 2, // root can't be collapsed
|
||||||
click: (event, data): boolean => {
|
click: (event: MouseEvent | JQuery.ClickEvent | JQuery.MouseDownEvent | React.PointerEvent<HTMLCanvasElement>, data): boolean => {
|
||||||
this.activityDetected();
|
this.activityDetected();
|
||||||
|
|
||||||
const targetType = data.targetType;
|
const targetType = data.targetType;
|
||||||
const node = data.node;
|
const node = data.node;
|
||||||
|
const ctrlKey = utils.isCtrlKey(event);
|
||||||
|
|
||||||
if (node.isSelected() && targetType === "icon") {
|
if (node.isSelected() && targetType === "icon") {
|
||||||
this.triggerCommand("openBulkActionsDialog", {
|
this.triggerCommand("openBulkActionsDialog", {
|
||||||
@ -356,7 +359,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
} else if (targetType === "title" || targetType === "icon") {
|
} else if (targetType === "title" || targetType === "icon") {
|
||||||
if (event.shiftKey) {
|
if (event.shiftKey && !ctrlKey) {
|
||||||
const activeNode = this.getActiveNode();
|
const activeNode = this.getActiveNode();
|
||||||
|
|
||||||
if (activeNode.getParent() !== node.getParent()) {
|
if (activeNode.getParent() !== node.getParent()) {
|
||||||
@ -381,9 +384,11 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
node.setFocus(true);
|
node.setFocus(true);
|
||||||
} else if ((!utils.isMac() && event.ctrlKey) || (utils.isMac() && event.metaKey)) {
|
} else if (ctrlKey) {
|
||||||
const notePath = treeService.getNotePath(node);
|
const notePath = treeService.getNotePath(node);
|
||||||
appContext.tabManager.openTabWithNoteWithHoisting(notePath);
|
appContext.tabManager.openTabWithNoteWithHoisting(notePath, {
|
||||||
|
activate: event.shiftKey ? true : false
|
||||||
|
});
|
||||||
} else if (event.altKey) {
|
} else if (event.altKey) {
|
||||||
node.setSelected(!node.isSelected());
|
node.setSelected(!node.isSelected());
|
||||||
node.setFocus(true);
|
node.setFocus(true);
|
||||||
|
@ -20,9 +20,10 @@ export default class AbstractTextTypeWidget extends TypeWidget {
|
|||||||
const isLeftClick = e.which === 1;
|
const isLeftClick = e.which === 1;
|
||||||
const isMiddleClick = e.which === 2;
|
const isMiddleClick = e.which === 2;
|
||||||
const ctrlKey = utils.isCtrlKey(e);
|
const ctrlKey = utils.isCtrlKey(e);
|
||||||
|
const activate = (isLeftClick && ctrlKey && e.shiftKey) || (isMiddleClick && e.shiftKey);
|
||||||
|
|
||||||
if ((isLeftClick && ctrlKey) || isMiddleClick) {
|
if ((isLeftClick && ctrlKey) || isMiddleClick) {
|
||||||
this.openImageInNewTab($(e.target));
|
this.openImageInNewTab($(e.target), activate);
|
||||||
} else if (isLeftClick && singleClickOpens) {
|
} else if (isLeftClick && singleClickOpens) {
|
||||||
this.openImageInCurrentTab($(e.target));
|
this.openImageInCurrentTab($(e.target));
|
||||||
}
|
}
|
||||||
@ -39,11 +40,11 @@ export default class AbstractTextTypeWidget extends TypeWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openImageInNewTab($img: JQuery<HTMLElement>) {
|
async openImageInNewTab($img: JQuery<HTMLElement>, activate: boolean = false) {
|
||||||
const parsedImage = await this.parseFromImage($img);
|
const parsedImage = await this.parseFromImage($img);
|
||||||
|
|
||||||
if (parsedImage) {
|
if (parsedImage) {
|
||||||
appContext.tabManager.openTabWithNoteWithHoisting(parsedImage.noteId, { viewScope: parsedImage.viewScope });
|
appContext.tabManager.openTabWithNoteWithHoisting(parsedImage.noteId, { activate, viewScope: parsedImage.viewScope });
|
||||||
} else {
|
} else {
|
||||||
window.open($img.prop("src"), "_blank");
|
window.open($img.prop("src"), "_blank");
|
||||||
}
|
}
|
||||||
|
47
apps/server-e2e/src/layout/open_note_and_activate.spec.ts
Normal file
47
apps/server-e2e/src/layout/open_note_and_activate.spec.ts
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import { test, expect } from "@playwright/test";
|
||||||
|
import App from "../support/app";
|
||||||
|
|
||||||
|
const NOTE_TITLE = "Trilium Integration Test DB";
|
||||||
|
|
||||||
|
test("Opens and activate a note from launcher Bar", async ({ page, context }) => {
|
||||||
|
const app = new App(page, context);
|
||||||
|
await app.goto();
|
||||||
|
await app.closeAllTabs();
|
||||||
|
|
||||||
|
const mapButton = app.launcherBar.locator(".launcher-button.bx-search.visible");
|
||||||
|
await expect(mapButton).toBeVisible();
|
||||||
|
|
||||||
|
await page.keyboard.down('Control');
|
||||||
|
await page.keyboard.down('Shift');
|
||||||
|
|
||||||
|
await mapButton.click();
|
||||||
|
|
||||||
|
await page.keyboard.up('Control');
|
||||||
|
await page.keyboard.up('Shift');
|
||||||
|
|
||||||
|
const tabs = app.tabBar.locator(".note-tab");
|
||||||
|
await expect(tabs).toHaveCount(2);
|
||||||
|
|
||||||
|
const secondTab = tabs.nth(1);
|
||||||
|
await expect(secondTab).toHaveAttribute('active', '');
|
||||||
|
});
|
||||||
|
|
||||||
|
test("Opens and activate a note from note tree", async ({ page, context }) => {
|
||||||
|
const app = new App(page, context);
|
||||||
|
await app.goto();
|
||||||
|
await app.closeAllTabs();
|
||||||
|
|
||||||
|
await page.keyboard.down('Control');
|
||||||
|
await page.keyboard.down('Shift');
|
||||||
|
|
||||||
|
await app.clickNoteOnNoteTreeByTitle(NOTE_TITLE);
|
||||||
|
|
||||||
|
await page.keyboard.up('Control');
|
||||||
|
await page.keyboard.up('Shift');
|
||||||
|
|
||||||
|
const tabs = app.tabBar.locator(".note-tab");
|
||||||
|
await expect(tabs).toHaveCount(2);
|
||||||
|
|
||||||
|
const secondTab = tabs.nth(1);
|
||||||
|
await expect(secondTab).toHaveAttribute('active', '');
|
||||||
|
});
|
@ -188,6 +188,12 @@ second line 2</code></pre><ul><li>Hello</li><li>world</li></ul><ol><li>Hello</li
|
|||||||
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("converts multiple inline math expressions into Mathtex format", () => {
|
||||||
|
const input = `Energy: $e=mc^{2}$, Force: $F=ma$.`;
|
||||||
|
const expected = /*html*/`<p>Energy: <span class="math-tex">\\(e=mc^{2}\\)</span>, Force: <span class="math-tex">\\(F=ma\\)</span>.</p>`;
|
||||||
|
expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected);
|
||||||
|
});
|
||||||
|
|
||||||
it("converts display math expressions into Mathtex format", () => {
|
it("converts display math expressions into Mathtex format", () => {
|
||||||
const input = `$$\sqrt{x^{2}+1}$$`;
|
const input = `$$\sqrt{x^{2}+1}$$`;
|
||||||
const expected = /*html*/`<p><span class="math-tex">\\[\sqrt{x^{2}+1}\\]</span></p>`;
|
const expected = /*html*/`<p><span class="math-tex">\\[\sqrt{x^{2}+1}\\]</span></p>`;
|
||||||
|
@ -25,7 +25,7 @@ class CustomMarkdownRenderer extends Renderer {
|
|||||||
`<span class="math-tex">\\\[$1\\\]</span>`);
|
`<span class="math-tex">\\\[$1\\\]</span>`);
|
||||||
|
|
||||||
// Inline math
|
// Inline math
|
||||||
text = text.replaceAll(/(?<!\\)\$(.+)\$/g,
|
text = text.replaceAll(/(?<!\\)\$(.+?)\$/g,
|
||||||
`<span class="math-tex">\\\($1\\\)</span>`);
|
`<span class="math-tex">\\\($1\\\)</span>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
## 🐞 Bugfixes
|
## 🐞 Bugfixes
|
||||||
|
|
||||||
* [Inconsistent Find and Replace Behavior in Large Code Notes](https://github.com/TriliumNext/Notes/issues/1826) by @SiriusXT
|
* [Inconsistent Find and Replace Behavior in Large Code Notes](https://github.com/TriliumNext/Notes/issues/1826) by @SiriusXT
|
||||||
|
* [Incorrect import of multiple inline math](https://github.com/TriliumNext/Notes/pull/1906) by @SiriusXT
|
||||||
|
|
||||||
## ✨ Improvements
|
## ✨ Improvements
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "^14.1.0",
|
"http-server": "^14.1.0",
|
||||||
"lint-staged": "^15.0.0",
|
"lint-staged": "^16.0.0",
|
||||||
"stylelint": "^16.0.0",
|
"stylelint": "^16.0.0",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "^14.1.0",
|
"http-server": "^14.1.0",
|
||||||
"lint-staged": "^15.0.0",
|
"lint-staged": "^16.0.0",
|
||||||
"stylelint": "^16.0.0",
|
"stylelint": "^16.0.0",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "^14.1.0",
|
"http-server": "^14.1.0",
|
||||||
"lint-staged": "^15.0.0",
|
"lint-staged": "^16.0.0",
|
||||||
"stylelint": "^16.0.0",
|
"stylelint": "^16.0.0",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "^14.1.0",
|
"http-server": "^14.1.0",
|
||||||
"lint-staged": "^15.0.0",
|
"lint-staged": "^16.0.0",
|
||||||
"stylelint": "^16.0.0",
|
"stylelint": "^16.0.0",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
"eslint": "^9.0.0",
|
"eslint": "^9.0.0",
|
||||||
"eslint-config-ckeditor5": ">=9.1.0",
|
"eslint-config-ckeditor5": ">=9.1.0",
|
||||||
"http-server": "^14.1.0",
|
"http-server": "^14.1.0",
|
||||||
"lint-staged": "^15.0.0",
|
"lint-staged": "^16.0.0",
|
||||||
"stylelint": "^16.0.0",
|
"stylelint": "^16.0.0",
|
||||||
"stylelint-config-ckeditor5": ">=9.1.0",
|
"stylelint-config-ckeditor5": ">=9.1.0",
|
||||||
"ts-node": "^10.9.1",
|
"ts-node": "^10.9.1",
|
||||||
|
695
pnpm-lock.yaml
generated
695
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user