mirror of
				https://github.com/zadam/trilium.git
				synced 2025-10-31 02:16:05 +01:00 
			
		
		
		
	expose add link on UI, fixes #95
This commit is contained in:
		
							
								
								
									
										1
									
								
								src/public/images/trilium.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/public/images/trilium.svg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enable-background="new 0 0 100 100" xml:space="preserve"><path d="M63.966,45.043c0.008-0.009,0.021-0.021,0.027-0.029c0.938-1.156-0.823-13.453-5.063-20.125  c-1.389-2.186-2.239-3.423-3.219-4.719c-3.907-5.166-6-6.125-6-6.125S35.732,24.78,36.149,44.315  c-1.754,0.065-11.218,7.528-14.826,14.388c-1.206,2.291-1.856,3.645-2.493,5.141c-2.539,5.957-2.33,8.25-2.33,8.25  s16.271,6.79,33.014-3.294c0.007,0.021,0.013,0.046,0.02,0.063c0.537,1.389,12.08,5.979,19.976,5.621  c2.587-0.116,4.084-0.238,5.696-0.444c6.424-0.818,8.298-2.157,8.298-2.157S81.144,54.396,63.966,45.043z M50.787,65.343  c1.059-1.183,4.648-5.853,0.995-11.315c-0.253-0.377-0.496-0.236-0.496-0.236s0.063,10.822-5.162,12.359  c-5.225,1.537-13.886,4.4-20.427,0.455C25,66.186,26.924,53.606,38.544,47.229c0.546,1.599,2.836,6.854,9.292,6.409  c0.453-0.031,0.453-0.313,0.453-0.313s-9.422-5.328-8.156-10.625s3.089-14.236,9.766-17.948c0.714-0.397,10.746,7.593,10.417,20.94  c-1.606-0.319-7.377-1.004-10.226,4.864c-0.198,0.409,0.046,0.549,0.046,0.549s9.31-5.521,13.275-1.789  c3.965,3.733,10.813,9.763,10.71,17.4C74.111,67.533,62.197,72.258,50.787,65.343z M35.613,35.145c0,0-0.991,3.241-0.603,7.524  l-13.393-7.524C21.618,35.145,27.838,30.931,35.613,35.145z M21.193,36.03l13.344,7.612c-3.872,1.872-6.142,4.388-6.142,4.388  C20.78,43.531,21.193,36.03,21.193,36.03z M72.287,49.064c0,0-2.321-2.471-6.23-4.263l13.187-7.881  C79.243,36.92,79.808,44.413,72.287,49.064z M78.687,36.113l-13.237,7.794c0.3-4.291-0.754-7.511-0.754-7.511  C72.383,32.025,78.687,36.113,78.687,36.113z M42.076,73.778c0,0,3.309-0.737,6.845-3.185l0.056,15.361  C48.977,85.955,42.244,82.621,42.076,73.778z M49.956,85.888L50,70.526c3.539,2.445,6.846,3.181,6.846,3.181  C56.686,82.551,49.956,85.888,49.956,85.888z"></path></svg> | ||||
| After Width: | Height: | Size: 1.8 KiB | 
| @@ -2,7 +2,8 @@ import cloningService from '../services/cloning.js'; | ||||
| import linkService from '../services/link.js'; | ||||
| import noteDetailService from '../services/note_detail.js'; | ||||
| import treeUtils from '../services/tree_utils.js'; | ||||
| import autocompleteService from '../services/autocomplete.js'; | ||||
| import server from "../services/server.js"; | ||||
| import noteDetailText from "../services/note_detail_text.js"; | ||||
|  | ||||
| const $dialog = $("#add-link-dialog"); | ||||
| const $form = $("#add-link-form"); | ||||
| @@ -11,6 +12,7 @@ const $linkTitle = $("#link-title"); | ||||
| const $clonePrefix = $("#clone-prefix"); | ||||
| const $linkTitleFormGroup = $("#add-link-title-form-group"); | ||||
| const $prefixFormGroup = $("#add-link-prefix-form-group"); | ||||
| const $linkTypeDiv = $("#add-link-type-div"); | ||||
| const $linkTypes = $("input[name='add-link-type']"); | ||||
| const $linkTypeHtml = $linkTypes.filter('input[value="html"]'); | ||||
|  | ||||
| @@ -52,8 +54,12 @@ async function showDialog() { | ||||
|     } | ||||
|  | ||||
|     $autoComplete.autocomplete({ | ||||
|         source: await autocompleteService.getAutocompleteItems(), | ||||
|         minLength: 0, | ||||
|         source: async function(request, response) { | ||||
|             const result = await server.get('autocomplete?query=' + encodeURIComponent(request.term)); | ||||
|  | ||||
|             response(result); | ||||
|         }, | ||||
|         minLength: 2, | ||||
|         change: async () => { | ||||
|             const val = $autoComplete.val(); | ||||
|             const notePath = linkService.getNodePathFromLabel(val); | ||||
| @@ -92,7 +98,16 @@ $form.submit(() => { | ||||
|  | ||||
|             $dialog.dialog("close"); | ||||
|  | ||||
|             linkService.addLinkToEditor(linkTitle, '#' + notePath); | ||||
|             const linkHref = '#' + notePath; | ||||
|  | ||||
|             if (hasSelection()) { | ||||
|                 const editor = noteDetailText.getEditor(); | ||||
|  | ||||
|                 editor.execute('link', linkHref); | ||||
|             } | ||||
|             else { | ||||
|                 linkService.addLinkToEditor(linkTitle, linkHref); | ||||
|             } | ||||
|         } | ||||
|         else if (linkType === 'selected-to-current') { | ||||
|             const prefix = $clonePrefix.val(); | ||||
| @@ -113,17 +128,21 @@ $form.submit(() => { | ||||
|     return false; | ||||
| }); | ||||
|  | ||||
| // returns true if user selected some text, false if there's no selection | ||||
| function hasSelection() { | ||||
|     const model = noteDetailText.getEditor().model; | ||||
|     const selection = model.document.selection; | ||||
|  | ||||
|     return !selection.isCollapsed; | ||||
| } | ||||
|  | ||||
| function linkTypeChanged() { | ||||
|     const value = $linkTypes.filter(":checked").val(); | ||||
|  | ||||
|     if (value === 'html') { | ||||
|         $linkTitleFormGroup.show(); | ||||
|         $prefixFormGroup.hide(); | ||||
|     } | ||||
|     else { | ||||
|         $linkTitleFormGroup.hide(); | ||||
|         $prefixFormGroup.show(); | ||||
|     } | ||||
|     $linkTitleFormGroup.toggle(!hasSelection() && value === 'html'); | ||||
|     $prefixFormGroup.toggle(!hasSelection() && value !== 'html'); | ||||
|  | ||||
|     $linkTypeDiv.toggle(!hasSelection()); | ||||
| } | ||||
|  | ||||
| $linkTypes.change(linkTypeChanged); | ||||
|   | ||||
| @@ -1,104 +0,0 @@ | ||||
| import treeCache from "./tree_cache.js"; | ||||
| import treeUtils from "./tree_utils.js"; | ||||
| import protectedSessionHolder from './protected_session_holder.js'; | ||||
|  | ||||
| async function getAutocompleteItems(parentNoteId, notePath, titlePath) { | ||||
|     if (!parentNoteId) { | ||||
|         parentNoteId = 'root'; | ||||
|     } | ||||
|  | ||||
|     const parentNote = await treeCache.getNote(parentNoteId); | ||||
|     const childNotes = await parentNote.getChildNotes(); | ||||
|  | ||||
|     if (!childNotes.length) { | ||||
|         return []; | ||||
|     } | ||||
|  | ||||
|     if (!notePath) { | ||||
|         notePath = ''; | ||||
|     } | ||||
|  | ||||
|     if (!titlePath) { | ||||
|         titlePath = ''; | ||||
|     } | ||||
|  | ||||
|     const autocompleteItems = []; | ||||
|  | ||||
|     for (const childNote of childNotes) { | ||||
|         if (childNote.hideInAutocomplete) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         const childNotePath = (notePath ? (notePath + '/') : '') + childNote.noteId; | ||||
|         const childTitlePath = (titlePath ? (titlePath + ' / ') : '') + await treeUtils.getNoteTitle(childNote.noteId, parentNoteId); | ||||
|  | ||||
|         if (!childNote.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) { | ||||
|             autocompleteItems.push({ | ||||
|                 value: childTitlePath + ' (' + childNotePath + ')', | ||||
|                 label: childTitlePath | ||||
|             }); | ||||
|         } | ||||
|  | ||||
|         const childItems = await getAutocompleteItems(childNote.noteId, childNotePath, childTitlePath); | ||||
|  | ||||
|         for (const childItem of childItems) { | ||||
|             autocompleteItems.push(childItem); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (parentNoteId === 'root') { | ||||
|         console.log(`Generated ${autocompleteItems.length} autocomplete items`); | ||||
|     } | ||||
|  | ||||
|     return autocompleteItems; | ||||
| } | ||||
|  | ||||
| // Overrides the default autocomplete filter function to search for matched on atleast 1 word in each of the input term's words | ||||
| $.ui.autocomplete.filter = (array, terms) => { | ||||
|     if (!terms) { | ||||
|         return array; | ||||
|     } | ||||
|  | ||||
|     const startDate = new Date(); | ||||
|  | ||||
|     const results = []; | ||||
|     const tokens = terms.toLowerCase().split(" "); | ||||
|  | ||||
|     for (const item of array) { | ||||
|         const lcLabel = item.label.toLowerCase(); | ||||
|  | ||||
|         const found = tokens.every(token => lcLabel.indexOf(token) !== -1); | ||||
|         if (!found) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         // this is not completely correct and might cause minor problems with note with names containing this " / " | ||||
|         const lastSegmentIndex = lcLabel.lastIndexOf(" / "); | ||||
|  | ||||
|         if (lastSegmentIndex !== -1) { | ||||
|             const lastSegment = lcLabel.substr(lastSegmentIndex + 3); | ||||
|  | ||||
|             // at least some token needs to be in the last segment (leaf note), otherwise this | ||||
|             // particular note is not that interesting (query is satisfied by parent note) | ||||
|             const foundInLastSegment = tokens.some(token => lastSegment.indexOf(token) !== -1); | ||||
|  | ||||
|             if (!foundInLastSegment) { | ||||
|                 continue; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         results.push(item); | ||||
|  | ||||
|         if (results.length > 100) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     console.log("Search took " + (new Date().getTime() - startDate.getTime()) + "ms"); | ||||
|  | ||||
|     return results; | ||||
| }; | ||||
|  | ||||
| export default { | ||||
|     getAutocompleteItems | ||||
| }; | ||||
							
								
								
									
										1
									
								
								src/public/javascripts/services/bootstrap.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								src/public/javascripts/services/bootstrap.js
									
									
									
									
										vendored
									
									
								
							| @@ -35,6 +35,7 @@ import libraryLoader from "./library_loader.js"; | ||||
| // required for CKEditor image upload plugin | ||||
| window.glob.getCurrentNode = treeService.getCurrentNode; | ||||
| window.glob.getHeaders = server.getHeaders; | ||||
| window.glob.showAddLinkDialog = addLinkDialog.showDialog; | ||||
|  | ||||
| // required for ESLint plugin | ||||
| window.glob.getCurrentNote = noteDetailService.getCurrentNote; | ||||
|   | ||||
							
								
								
									
										2
									
								
								src/public/libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								src/public/libraries/ckeditor/ckeditor.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @@ -56,7 +56,7 @@ async function checkContentHashes(otherHashes) { | ||||
|         if (hashes[key] !== otherHashes[key]) { | ||||
|             allChecksPassed = false; | ||||
|  | ||||
|             await eventLogService.addEvent(`Content hash check for ${key} FAILED. Local is ${hashes[key]}, remote is ${resp.hashes[key]}`); | ||||
|             await eventLogService.addEvent(`Content hash check for ${key} FAILED. Local is ${hashes[key]}, remote is ${otherHashes[key]}`); | ||||
|  | ||||
|             if (key !== 'recent_notes') { | ||||
|                 // let's not get alarmed about recent notes which get updated often and can cause failures in race conditions | ||||
|   | ||||
| @@ -220,7 +220,7 @@ | ||||
|  | ||||
|     <div id="add-link-dialog" title="Add link" style="display: none;"> | ||||
|       <form id="add-link-form"> | ||||
|         <div class="radio"> | ||||
|         <div id="add-link-type-div" class="radio"> | ||||
|           <label title="Add HTML link to the selected note at cursor in current note"> | ||||
|             <input type="radio" name="add-link-type" value="html"/> | ||||
|             add normal HTML link</label> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user