mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 04:51:31 +08:00 
			
		
		
		
	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:
		
						commit
						cc02546ed3
					
				| @ -8,6 +8,7 @@ import contextMenu from "./menus/context_menu.js"; | |||||||
| import DesktopLayout from "./layouts/desktop_layout.js"; | import DesktopLayout from "./layouts/desktop_layout.js"; | ||||||
| import glob from "./services/glob.js"; | import glob from "./services/glob.js"; | ||||||
| import zoomService from './components/zoom.js'; | import zoomService from './components/zoom.js'; | ||||||
|  | import options from "./services/options.js"; | ||||||
| 
 | 
 | ||||||
| bundleService.getWidgetBundlesByParent().then(widgetBundles => { | bundleService.getWidgetBundlesByParent().then(widgetBundles => { | ||||||
|     appContext.setLayout(new DesktopLayout(widgetBundles)); |     appContext.setLayout(new DesktopLayout(widgetBundles)); | ||||||
| @ -115,11 +116,27 @@ if (utils.isElectron()) { | |||||||
|                 ? (`${params.selectionText.substr(0, 13)}…`) |                 ? (`${params.selectionText.substr(0, 13)}…`) | ||||||
|                 : params.selectionText; |                 : 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({ |             items.push({ | ||||||
|                 enabled: editFlags.canPaste, |                 enabled: editFlags.canPaste, | ||||||
|                 title: `Search for "${shortenedSelection}" with DuckDuckGo`, |                 title: `Search for "${shortenedSelection}" with ${searchEngineName}`, | ||||||
|                 uiIcon: "bx bx-search-alt", |                 uiIcon: "bx bx-search-alt", | ||||||
|                 handler: () => electron.shell.openExternal(`https://duckduckgo.com/?q=${encodeURIComponent(params.selectionText)}`) |                 handler: () => electron.shell.openExternal(searchUrl) | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ import PasswordOptions from "./options/password.js"; | |||||||
| import EtapiOptions from "./options/etapi.js"; | import EtapiOptions from "./options/etapi.js"; | ||||||
| import BackupOptions from "./options/backup.js"; | import BackupOptions from "./options/backup.js"; | ||||||
| import SyncOptions from "./options/sync.js"; | import SyncOptions from "./options/sync.js"; | ||||||
|  | import SearchEngineOptions from "./options/other/search_engine.js"; | ||||||
| import TrayOptions from "./options/other/tray.js"; | import TrayOptions from "./options/other/tray.js"; | ||||||
| import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js"; | import NoteErasureTimeoutOptions from "./options/other/note_erasure_timeout.js"; | ||||||
| import NoteRevisionsSnapshotIntervalOptions from "./options/other/note_revisions_snapshot_interval.js"; | import NoteRevisionsSnapshotIntervalOptions from "./options/other/note_revisions_snapshot_interval.js"; | ||||||
| @ -76,6 +77,7 @@ const CONTENT_WIDGETS = { | |||||||
|     _optionsBackup: [ BackupOptions ], |     _optionsBackup: [ BackupOptions ], | ||||||
|     _optionsSync: [ SyncOptions ], |     _optionsSync: [ SyncOptions ], | ||||||
|     _optionsOther: [ |     _optionsOther: [ | ||||||
|  |         SearchEngineOptions, | ||||||
|         TrayOptions, |         TrayOptions, | ||||||
|         NoteErasureTimeoutOptions, |         NoteErasureTimeoutOptions, | ||||||
|         AttachmentErasureTimeoutOptions, |         AttachmentErasureTimeoutOptions, | ||||||
|  | |||||||
| @ -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; | ||||||
|  |     } | ||||||
|  | } | ||||||
| @ -62,7 +62,10 @@ const ALLOWED_OPTIONS = new Set([ | |||||||
|     'minTocHeadings', |     'minTocHeadings', | ||||||
|     'checkForUpdates', |     'checkForUpdates', | ||||||
|     'disableTray', |     'disableTray', | ||||||
|     'eraseUnusedImageAttachmentsAfterSeconds' |     'eraseUnusedImageAttachmentsAfterSeconds', | ||||||
|  |     'disableTray', | ||||||
|  |     'customSearchEngineName', | ||||||
|  |     'customSearchEngineUrl', | ||||||
| ]); | ]); | ||||||
| 
 | 
 | ||||||
| function getOptions() { | function getOptions() { | ||||||
|  | |||||||
| @ -318,6 +318,7 @@ async function exportToZip(taskContext, branch, format, res, setHeaders = true) | |||||||
|         if (noteMeta.format === 'html') { |         if (noteMeta.format === 'html') { | ||||||
|             if (!content.substr(0, 100).toLowerCase().includes("<html")) { |             if (!content.substr(0, 100).toLowerCase().includes("<html")) { | ||||||
|                 const cssUrl = `${"../".repeat(noteMeta.notePath.length - 1)}style.css`; |                 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
 |                 // <base> element will make sure external links are openable - https://github.com/zadam/trilium/issues/1289#issuecomment-704066809
 | ||||||
|                 content = `<html>
 |                 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"> |     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||||
|     <link rel="stylesheet" href="${cssUrl}"> |     <link rel="stylesheet" href="${cssUrl}"> | ||||||
|     <base target="_parent"> |     <base target="_parent"> | ||||||
|  |     <title data-trilium-title>${htmlTitle}</title> | ||||||
| </head> | </head> | ||||||
| <body> | <body> | ||||||
|   <div class="content"> |   <div class="content"> | ||||||
|       <h1>${utils.escapeHtml(title)}</h1> |       <h1 data-trilium-h1>${htmlTitle}</h1> | ||||||
|        |        | ||||||
|       <div class="ck-content">${content}</div> |       <div class="ck-content">${content}</div> | ||||||
|   </div> |   </div> | ||||||
| @ -504,7 +506,7 @@ ${markdownContent}`; | |||||||
|     const rootMeta = createNoteMeta(branch, { notePath: [] }, existingFileNames); |     const rootMeta = createNoteMeta(branch, { notePath: [] }, existingFileNames); | ||||||
| 
 | 
 | ||||||
|     const metaFile = { |     const metaFile = { | ||||||
|         formatVersion: 1, |         formatVersion: 2, | ||||||
|         appVersion: packageInfo.version, |         appVersion: packageInfo.version, | ||||||
|         files: [ rootMeta ] |         files: [ rootMeta ] | ||||||
|     }; |     }; | ||||||
|  | |||||||
| @ -314,6 +314,8 @@ async function importZip(taskContext, fileBuffer, importRootNote) { | |||||||
|             return /^(?:[a-z]+:)?\/\//i.test(url); |             return /^(?:[a-z]+:)?\/\//i.test(url); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         content = removeTrilumTags(content); | ||||||
|  | 
 | ||||||
|         content = content.replace(/<h1>([^<]*)<\/h1>/gi, (match, text) => { |         content = content.replace(/<h1>([^<]*)<\/h1>/gi, (match, text) => { | ||||||
|             if (noteTitle.trim() === text.trim()) { |             if (noteTitle.trim() === text.trim()) { | ||||||
|                 return ""; // remove whole H1 tag
 |                 return ""; // remove whole H1 tag
 | ||||||
| @ -403,6 +405,18 @@ async function importZip(taskContext, fileBuffer, importRootNote) { | |||||||
|         return content; |         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 {NoteMeta} noteMeta | ||||||
|      * @param {string} type |      * @param {string} type | ||||||
|  | |||||||
| @ -89,6 +89,8 @@ const defaultOptions = [ | |||||||
|     { name: 'checkForUpdates', value: 'true', isSynced: true }, |     { name: 'checkForUpdates', value: 'true', isSynced: true }, | ||||||
|     { name: 'disableTray', value: 'false', isSynced: false }, |     { name: 'disableTray', value: 'false', isSynced: false }, | ||||||
|     { name: 'eraseUnusedImageAttachmentsAfterSeconds', value: '86400', 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() { | function initStartupOptions() { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 zadam
						zadam