Merge remote-tracking branch 'origin/master' into next60

# Conflicts:
#	src/routes/api/options.js
#	src/services/import/zip.js
#	src/services/options_init.js
This commit is contained in:
zadam 2023-05-07 09:41:33 +02:00
commit cc02546ed3
7 changed files with 123 additions and 5 deletions

View File

@ -8,6 +8,7 @@ import contextMenu from "./menus/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));
@ -115,11 +116,27 @@ if (utils.isElectron()) {
? (`${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 DuckDuckGo`,
title: `Search for "${shortenedSelection}" with ${searchEngineName}`,
uiIcon: "bx bx-search-alt",
handler: () => electron.shell.openExternal(`https://duckduckgo.com/?q=${encodeURIComponent(params.selectionText)}`)
handler: () => electron.shell.openExternal(searchUrl)
});
}

View File

@ -18,6 +18,7 @@ import PasswordOptions from "./options/password.js";
import EtapiOptions from "./options/etapi.js";
import BackupOptions from "./options/backup.js";
import SyncOptions from "./options/sync.js";
import SearchEngineOptions from "./options/other/search_engine.js";
import TrayOptions from "./options/other/tray.js";
import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js";
import NoteRevisionsSnapshotIntervalOptions from "./options/other/note_revisions_snapshot_interval.js";
@ -76,6 +77,7 @@ const CONTENT_WIDGETS = {
_optionsBackup: [ BackupOptions ],
_optionsSync: [ SyncOptions ],
_optionsOther: [
SearchEngineOptions,
TrayOptions,
NoteErasureTimeoutOptions,
AttachmentErasureTimeoutOptions,

View File

@ -0,0 +1,78 @@
import OptionsWidget from "../options_widget.js";
import utils from "../../../../services/utils.js";
const TPL = `
<div class="options-section">
<h4>Search Engine</h4>
<p>Custom search engine requires both a name and a URL to be set. If either of these is not set, DuckDuckGo will be used as the default search engine.</p>
<form class="sync-setup-form">
<div class="form-group">
<label>Predefined search engine templates</label>
<select class="predefined-search-engine-select form-control">
<option value="Bing">Bing</option>
<option value="Baidu">Baidu</option>
<option value="Duckduckgo">Duckduckgo</option>
<option value="Google">Google</option>
</select>
</div>
<div class="form-group">
<label>Custom search engine name</label>
<input type="text" class="custom-search-engine-name form-control" placeholder="Customize search engine name">
</div>
<div class="form-group">
<label>Custom search engine URL should include <code>{keyword}</code> as a placeholder for the search term.</label>
<input type="text" class="custom-search-engine-url form-control" placeholder="Customize search engine url">
</div>
<div style="display: flex; justify-content: space-between;">
<button class="btn btn-primary">Save</button>
</div>
</form>
</div>`;
const SEARCH_ENGINES = {
"Bing": "https://www.bing.com/search?q={keyword}",
"Baidu": "https://www.baidu.com/s?wd={keyword}",
"Duckduckgo": "https://duckduckgo.com/?q={keyword}",
"Google": "https://www.google.com/search?q={keyword}",
}
export default class SearchEngineOptions extends OptionsWidget {
isEnabled() {
return super.isEnabled() && utils.isElectron();
}
doRender() {
this.$widget = $(TPL);
this.$form = this.$widget.find(".sync-setup-form");
this.$predefinedSearchEngineSelect = this.$widget.find(".predefined-search-engine-select");
this.$customSearchEngineName = this.$widget.find(".custom-search-engine-name");
this.$customSearchEngineUrl = this.$widget.find(".custom-search-engine-url");
this.$predefinedSearchEngineSelect.on('change', () => {
const predefinedSearchEngine = this.$predefinedSearchEngineSelect.val();
this.$customSearchEngineName[0].value = predefinedSearchEngine;
this.$customSearchEngineUrl[0].value = SEARCH_ENGINES[predefinedSearchEngine];
});
this.$form.on('submit', () => {
this.updateMultipleOptions({
'customSearchEngineName': this.$customSearchEngineName.val(),
'customSearchEngineUrl': this.$customSearchEngineUrl.val()
});
});
}
async optionsLoaded(options) {
this.$predefinedSearchEngineSelect.val("");
this.$customSearchEngineName[0].value = options.customSearchEngineName;
this.$customSearchEngineUrl[0].value = options.customSearchEngineUrl;
}
}

View File

@ -62,7 +62,10 @@ const ALLOWED_OPTIONS = new Set([
'minTocHeadings',
'checkForUpdates',
'disableTray',
'eraseUnusedImageAttachmentsAfterSeconds'
'eraseUnusedImageAttachmentsAfterSeconds',
'disableTray',
'customSearchEngineName',
'customSearchEngineUrl',
]);
function getOptions() {

View File

@ -318,6 +318,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
if (noteMeta.format === 'html') {
if (!content.substr(0, 100).toLowerCase().includes("<html")) {
const cssUrl = `${"../".repeat(noteMeta.notePath.length - 1)}style.css`;
const htmlTitle = utils.escapeHtml(title);
// <base> element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809
content = `<html>
@ -326,10 +327,11 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true)
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="${cssUrl}">
<base target="_parent">
<title data-trilium-title>${htmlTitle}</title>
</head>
<body>
<div class="content">
<h1>${utils.escapeHtml(title)}</h1>
<h1 data-trilium-h1>${htmlTitle}</h1>
<div class="ck-content">${content}</div>
</div>
@ -504,7 +506,7 @@ ${markdownContent}`;
const rootMeta = createNoteMeta(branch, { notePath: [] }, existingFileNames);
const metaFile = {
formatVersion: 1,
formatVersion: 2,
appVersion: packageInfo.version,
files: [ rootMeta ]
};

View File

@ -314,6 +314,8 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
return /^(?:[a-z]+:)?\/\//i.test(url);
}
content = removeTrilumTags(content);
content = content.replace(/<h1>([^<]*)<\/h1>/gi, (match, text) => {
if (noteTitle.trim() === text.trim()) {
return ""; // remove whole H1 tag
@ -403,6 +405,18 @@ async function importZip(taskContext, fileBuffer, importRootNote) {
return content;
}
function removeTrilumTags(content) {
const tagsToRemove = [
'<h1 data-trilium-h1>([^<]*)<\/h1>',
'<title data-trilium-title>([^<]*)<\/title>'
]
for (const tag of tagsToRemove) {
let re = new RegExp(tag, "gi");
content = content.replace(re, '');
}
return content;
}
/**
* @param {NoteMeta} noteMeta
* @param {string} type

View File

@ -89,6 +89,8 @@ const defaultOptions = [
{ name: 'checkForUpdates', value: 'true', isSynced: true },
{ name: 'disableTray', value: 'false', isSynced: false },
{ name: 'eraseUnusedImageAttachmentsAfterSeconds', value: '86400', isSynced: false },
{ name: 'customSearchEngineName', value: 'Duckduckgo', isSynced: false },
{ name: 'customSearchEngineUrl', value: 'https://duckduckgo.com/?q={keyword}', isSynced: false },
];
function initStartupOptions() {