can't allow opening externally on attachment list

This commit is contained in:
zadam 2023-05-07 10:43:51 +02:00
parent cc02546ed3
commit 8284c673f9
10 changed files with 174 additions and 151 deletions

View File

@ -76,6 +76,10 @@ class AppContext extends Component {
$("body").append($renderedWidget);
$renderedWidget.on('click', "[data-trigger-command]", function() {
if ($(this).hasClass("disabled")) {
return;
}
const commandName = $(this).attr('data-trigger-command');
const $component = $(this).closest(".component");
const component = $component.prop("component");

View File

@ -4,11 +4,9 @@ import noteTooltipService from './services/note_tooltip.js';
import bundleService from "./services/bundle.js";
import noteAutocompleteService from './services/note_autocomplete.js';
import macInit from './services/mac_init.js';
import contextMenu from "./menus/context_menu.js";
import electronContextMenu from "./menus/electron_context_menu.js";
import DesktopLayout from "./layouts/desktop_layout.js";
import glob from "./services/glob.js";
import zoomService from './components/zoom.js';
import options from "./services/options.js";
bundleService.getWidgetBundlesByParent().then(widgetBundles => {
appContext.setLayout(new DesktopLayout(widgetBundles));
@ -18,9 +16,8 @@ bundleService.getWidgetBundlesByParent().then(widgetBundles => {
glob.setupGlobs();
if (utils.isElectron()) {
utils.dynamicRequire('electron').ipcRenderer.on('globalShortcut', async function(event, actionName) {
appContext.triggerCommand(actionName);
});
utils.dynamicRequire('electron').ipcRenderer.on('globalShortcut',
async (event, actionName) => appContext.triggerCommand(actionName));
}
macInit.init();
@ -30,131 +27,5 @@ noteTooltipService.setupGlobalTooltip();
noteAutocompleteService.init();
if (utils.isElectron()) {
const electron = utils.dynamicRequire('electron');
const remote = utils.dynamicRequire('@electron/remote');
const {webContents} = remote.getCurrentWindow();
webContents.on('context-menu', (event, params) => {
const {editFlags} = params;
const hasText = params.selectionText.trim().length > 0;
const isMac = process.platform === "darwin";
const platformModifier = isMac ? 'Meta' : 'Ctrl';
const items = [];
if (params.misspelledWord) {
for (const suggestion of params.dictionarySuggestions) {
items.push({
title: suggestion,
command: "replaceMisspelling",
spellingSuggestion: suggestion,
uiIcon: "bx bx-empty"
});
}
items.push({
title: `Add "${params.misspelledWord}" to dictionary`,
uiIcon: "bx bx-plus",
handler: () => webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord)
});
items.push({ title: `----` });
}
if (params.isEditable) {
items.push({
enabled: editFlags.canCut && hasText,
title: `Cut <kbd>${platformModifier}+X`,
uiIcon: "bx bx-cut",
handler: () => webContents.cut()
});
}
if (params.isEditable || hasText) {
items.push({
enabled: editFlags.canCopy && hasText,
title: `Copy <kbd>${platformModifier}+C`,
uiIcon: "bx bx-copy",
handler: () => webContents.copy()
});
}
if (!["", "javascript:", "about:blank#blocked"].includes(params.linkURL) && params.mediaType === 'none') {
items.push({
title: `Copy link`,
uiIcon: "bx bx-copy",
handler: () => {
electron.clipboard.write({
bookmark: params.linkText,
text: params.linkURL
});
}
});
}
if (params.isEditable) {
items.push({
enabled: editFlags.canPaste,
title: `Paste <kbd>${platformModifier}+V`,
uiIcon: "bx bx-paste",
handler: () => webContents.paste()
});
}
if (params.isEditable) {
items.push({
enabled: editFlags.canPaste,
title: `Paste as plain text <kbd>${platformModifier}+Shift+V`,
uiIcon: "bx bx-paste",
handler: () => webContents.pasteAndMatchStyle()
});
}
if (hasText) {
const shortenedSelection = params.selectionText.length > 15
? (`${params.selectionText.substr(0, 13)}`)
: params.selectionText;
// Read the search engine from the options and fallback to DuckDuckGo if the option is not set.
const customSearchEngineName = options.get("customSearchEngineName");
const customSearchEngineUrl = options.get("customSearchEngineUrl");
let searchEngineName;
let searchEngineUrl;
if (customSearchEngineName && customSearchEngineUrl) {
searchEngineName = customSearchEngineName;
searchEngineUrl = customSearchEngineUrl;
} else {
searchEngineName = "Duckduckgo";
searchEngineUrl = "https://duckduckgo.com/?q={keyword}";
}
// Replace the placeholder with the real search keyword.
let searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText));
items.push({
enabled: editFlags.canPaste,
title: `Search for "${shortenedSelection}" with ${searchEngineName}`,
uiIcon: "bx bx-search-alt",
handler: () => electron.shell.openExternal(searchUrl)
});
}
if (items.length === 0) {
return;
}
const zoomLevel = zoomService.getCurrentZoom();
contextMenu.show({
x: params.x / zoomLevel,
y: params.y / zoomLevel,
items,
selectMenuItemHandler: ({command, spellingSuggestion}) => {
if (command === 'replaceMisspelling') {
webContents.insertText(spellingSuggestion);
}
}
});
});
electronContextMenu.setupContextMenu();
}

View File

@ -0,0 +1,138 @@
import utils from "../services/utils.js";
import options from "../services/options.js";
import zoomService from "../components/zoom.js";
import contextMenu from "./context_menu.js";
function setupContextMenu() {
const electron = utils.dynamicRequire('electron');
const remote = utils.dynamicRequire('@electron/remote');
const {webContents} = remote.getCurrentWindow();
webContents.on('context-menu', (event, params) => {
const {editFlags} = params;
const hasText = params.selectionText.trim().length > 0;
const isMac = process.platform === "darwin";
const platformModifier = isMac ? 'Meta' : 'Ctrl';
const items = [];
if (params.misspelledWord) {
for (const suggestion of params.dictionarySuggestions) {
items.push({
title: suggestion,
command: "replaceMisspelling",
spellingSuggestion: suggestion,
uiIcon: "bx bx-empty"
});
}
items.push({
title: `Add "${params.misspelledWord}" to dictionary`,
uiIcon: "bx bx-plus",
handler: () => webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord)
});
items.push({ title: `----` });
}
if (params.isEditable) {
items.push({
enabled: editFlags.canCut && hasText,
title: `Cut <kbd>${platformModifier}+X`,
uiIcon: "bx bx-cut",
handler: () => webContents.cut()
});
}
if (params.isEditable || hasText) {
items.push({
enabled: editFlags.canCopy && hasText,
title: `Copy <kbd>${platformModifier}+C`,
uiIcon: "bx bx-copy",
handler: () => webContents.copy()
});
}
if (!["", "javascript:", "about:blank#blocked"].includes(params.linkURL) && params.mediaType === 'none') {
items.push({
title: `Copy link`,
uiIcon: "bx bx-copy",
handler: () => {
electron.clipboard.write({
bookmark: params.linkText,
text: params.linkURL
});
}
});
}
if (params.isEditable) {
items.push({
enabled: editFlags.canPaste,
title: `Paste <kbd>${platformModifier}+V`,
uiIcon: "bx bx-paste",
handler: () => webContents.paste()
});
}
if (params.isEditable) {
items.push({
enabled: editFlags.canPaste,
title: `Paste as plain text <kbd>${platformModifier}+Shift+V`,
uiIcon: "bx bx-paste",
handler: () => webContents.pasteAndMatchStyle()
});
}
if (hasText) {
const shortenedSelection = params.selectionText.length > 15
? (`${params.selectionText.substr(0, 13)}`)
: params.selectionText;
// Read the search engine from the options and fallback to DuckDuckGo if the option is not set.
const customSearchEngineName = options.get("customSearchEngineName");
const customSearchEngineUrl = options.get("customSearchEngineUrl");
let searchEngineName;
let searchEngineUrl;
if (customSearchEngineName && customSearchEngineUrl) {
searchEngineName = customSearchEngineName;
searchEngineUrl = customSearchEngineUrl;
} else {
searchEngineName = "Duckduckgo";
searchEngineUrl = "https://duckduckgo.com/?q={keyword}";
}
// Replace the placeholder with the real search keyword.
let searchUrl = searchEngineUrl.replace("{keyword}", encodeURIComponent(params.selectionText));
items.push({
enabled: editFlags.canPaste,
title: `Search for "${shortenedSelection}" with ${searchEngineName}`,
uiIcon: "bx bx-search-alt",
handler: () => electron.shell.openExternal(searchUrl)
});
}
if (items.length === 0) {
return;
}
const zoomLevel = zoomService.getCurrentZoom();
contextMenu.show({
x: params.x / zoomLevel,
y: params.y / zoomLevel,
items,
selectMenuItemHandler: ({command, spellingSuggestion}) => {
if (command === 'replaceMisspelling') {
webContents.insertText(spellingSuggestion);
}
}
});
});
}
export default {
setupContextMenu
};

View File

@ -27,7 +27,7 @@ async function mouseEnterHandler() {
return;
}
// this is to avoid showing tooltip from inside CKEditor link editor dialog
// this is to avoid showing tooltip from inside the CKEditor link editor dialog
if ($link.closest(".ck-link-actions").length) {
return;
}

View File

@ -67,13 +67,13 @@ const TPL = `
</div>`;
export default class AttachmentDetailWidget extends BasicWidget {
constructor(attachment) {
constructor(attachment, isFullDetail) {
super();
this.contentSized();
this.attachment = attachment;
this.attachmentActionsWidget = new AttachmentActionsWidget(attachment);
this.isFullDetail = true;
this.attachmentActionsWidget = new AttachmentActionsWidget(attachment, isFullDetail);
this.isFullDetail = isFullDetail;
this.child(this.attachmentActionsWidget);
}

View File

@ -29,10 +29,8 @@ const TPL = `
aria-expanded="false" class="icon-action icon-action-always-border bx bx-dots-vertical-rounded"></button>
<div class="dropdown-menu dropdown-menu-right">
<a data-trigger-command="openAttachment" class="dropdown-item">Open</a>
<a data-trigger-command="openAttachmentExternally" class="dropdown-item"
title="File will be open in an external application and watched for changes. You'll then be able to upload the modified version back to Trilium.">
Open externally</a>
<a data-trigger-command="openAttachment" class="dropdown-item"
title="File will be open in an external application and watched for changes. You'll then be able to upload the modified version back to Trilium.">Open externally</a>
<a data-trigger-command="downloadAttachment" class="dropdown-item">Download</a>
<a data-trigger-command="uploadNewAttachmentRevision" class="dropdown-item">Upload new revision</a>
<a data-trigger-command="copyAttachmentReferenceToClipboard" class="dropdown-item">Copy reference to clipboard</a>
@ -44,10 +42,11 @@ const TPL = `
</div>`;
export default class AttachmentActionsWidget extends BasicWidget {
constructor(attachment) {
constructor(attachment, isFullDetail) {
super();
this.attachment = attachment;
this.isFullDetail = isFullDetail;
}
get attachmentId() {
@ -83,6 +82,17 @@ export default class AttachmentActionsWidget extends BasicWidget {
toastService.showError("Upload of a new attachment revision failed.");
}
});
if (!this.isFullDetail) {
// we deactivate this button because the WatchedFileUpdateStatusWidget assumes only one visible attachment
// in a note context, so it doesn't work in a list
const $openAttachmentButton = this.$widget.find("[data-trigger-command='openAttachment']");
$openAttachmentButton
.addClass("disabled")
.append($('<span class="disabled-tooltip"> (?)</span>')
.attr("title", "Opening attachment externally is available only from the detail page, please first click on the attachment detail first and repeat the action.")
);
}
}
async openAttachmentCommand() {
@ -101,10 +111,6 @@ export default class AttachmentActionsWidget extends BasicWidget {
this.parent.copyAttachmentReferenceToClipboard();
}
async openAttachmentExternallyCommand() {
await openService.openAttachmentExternally(this.attachmentId, this.attachment.mime);
}
async deleteAttachmentCommand() {
if (!await dialogService.confirm(`Are you sure you want to delete attachment '${this.attachment.title}'?`)) {
return;

View File

@ -37,8 +37,7 @@ export default class AttachmentDetailTypeWidget extends TypeWidget {
return;
}
const attachmentDetailWidget = new AttachmentDetailWidget(attachment);
attachmentDetailWidget.isFullDetail = true;
const attachmentDetailWidget = new AttachmentDetailWidget(attachment, true);
this.child(attachmentDetailWidget);
this.$wrapper.append(attachmentDetailWidget.render());

View File

@ -39,8 +39,7 @@ export default class AttachmentListTypeWidget extends TypeWidget {
}
for (const attachment of attachments) {
const attachmentDetailWidget = new AttachmentDetailWidget(attachment);
attachmentDetailWidget.isFullDetail = false;
const attachmentDetailWidget = new AttachmentDetailWidget(attachment, false);
this.child(attachmentDetailWidget);

View File

@ -12,7 +12,7 @@ const TPL = `
</style>
<p>File <code class="file-path"></code> has been last modified on <span class="file-last-modified"></span>.</p>
<div style="display: flex; flex-direction: row; justify-content: space-evenly;">
<button class="btn btn-sm file-upload-button">Upload modified file</button>

View File

@ -195,6 +195,12 @@ div.ui-tooltip {
pointer-events: none;
}
.dropdown-menu .disabled .disabled-tooltip {
pointer-events: all;
color: var(--menu-text-color);
cursor: help;
}
.dropdown-menu a:hover:not(.disabled), .dropdown-item:hover:not(.disabled) {
color: var(--hover-item-text-color) !important;
background-color: var(--hover-item-background-color) !important;