mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-10-31 13:01:31 +08:00 
			
		
		
		
	client: port ts
This commit is contained in:
		
							parent
							
								
									4f7f7c460a
								
							
						
					
					
						commit
						f68347f92c
					
				
							
								
								
									
										26
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								src/public/app/types.d.ts
									
									
									
									
										vendored
									
									
								
							| @ -95,7 +95,11 @@ declare global { | ||||
|             className: string; | ||||
|             separateWordSearch: boolean; | ||||
|             caseSensitive: boolean; | ||||
|         }) | ||||
|             done: () => void; | ||||
|         }); | ||||
|         unmark(opts?: { | ||||
|             done: () => void; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     interface JQueryStatic { | ||||
| @ -221,9 +225,23 @@ declare global { | ||||
|         setOption(name: string, value: string); | ||||
|         refresh(); | ||||
|         focus(); | ||||
|         getCursor(): { line: number, col: number, ch: number }; | ||||
|         setCursor(line: number, col: number); | ||||
|         lineCount(): number; | ||||
|         on(event: string, callback: () => void); | ||||
|         operation(callback: () => void); | ||||
|         scrollIntoView(pos: number); | ||||
|         doc: { | ||||
|             getValue(): string; | ||||
|             markText( | ||||
|                 from: { line: number, ch: number } | number, | ||||
|                 to: { line: number, ch: number } | number, | ||||
|                 opts: { | ||||
|                     className: string | ||||
|                 }); | ||||
|             setSelection(from: number, to: number); | ||||
|             replaceRange(text: string, from: number, to: number); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     var katex: { | ||||
| @ -260,6 +278,7 @@ declare global { | ||||
|                 getRoot(): TextEditorElement; | ||||
|                 selection: { | ||||
|                     getFirstPosition(): undefined | TextPosition; | ||||
|                     getLastPosition(): undefined | TextPosition; | ||||
|                 } | ||||
|             }, | ||||
|             change(cb: (writer: Writer) => void) | ||||
| @ -283,13 +302,16 @@ declare global { | ||||
|                         } | ||||
|                     }; | ||||
|                 } | ||||
|                 change(cb: (writer: Writer) => void) | ||||
|                 change(cb: (writer: Writer) => void); | ||||
|                 scrollToTheSelection(): void; | ||||
|             } | ||||
|         }, | ||||
|         getData(): string; | ||||
|         setData(data: string): void; | ||||
|         getSelectedHtml(): string; | ||||
|         removeSelection(): void; | ||||
|         execute(action: string, ...args: unknown[]): void; | ||||
|         focus(): void; | ||||
|         sourceElement: HTMLElement; | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -2,35 +2,54 @@ | ||||
| // uses for highlighting matches, use the same one on CodeMirror
 | ||||
| // for consistency
 | ||||
| import utils from "../services/utils.js"; | ||||
| import type FindWidget from "./find.js"; | ||||
| 
 | ||||
| const FIND_RESULT_SELECTED_CSS_CLASSNAME = "ck-find-result_selected"; | ||||
| const FIND_RESULT_CSS_CLASSNAME = "ck-find-result"; | ||||
| 
 | ||||
| // TODO: Deduplicate.
 | ||||
| interface Match { | ||||
|     className: string; | ||||
|     clear(): void; | ||||
|     find(): { | ||||
|         from: number; | ||||
|         to: number; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| export default class FindInCode { | ||||
|     constructor(parent) { | ||||
|         /** @property {FindWidget} */ | ||||
| 
 | ||||
|     private parent: FindWidget; | ||||
|     private findResult?: Match[] | null; | ||||
| 
 | ||||
|     constructor(parent: FindWidget) { | ||||
|         this.parent = parent; | ||||
|     } | ||||
| 
 | ||||
|     async getCodeEditor() { | ||||
|         return this.parent.noteContext.getCodeEditor(); | ||||
|         return this.parent.noteContext?.getCodeEditor(); | ||||
|     } | ||||
| 
 | ||||
|     async performFind(searchTerm, matchCase, wholeWord) { | ||||
|         let findResult = null; | ||||
|     async performFind(searchTerm: string, matchCase: boolean, wholeWord: boolean) { | ||||
|         let findResult: Match[] | null = null; | ||||
|         let totalFound = 0; | ||||
|         let currentFound = -1; | ||||
| 
 | ||||
|         // See https://codemirror.net/addon/search/searchcursor.js for tips
 | ||||
|         const codeEditor = await this.getCodeEditor(); | ||||
|         if (!codeEditor) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const doc = codeEditor.doc; | ||||
|         const text = doc.getValue(); | ||||
| 
 | ||||
|         // Clear all markers
 | ||||
|         if (this.findResult != null) { | ||||
|         if (this.findResult) { | ||||
|             codeEditor.operation(() => { | ||||
|                 for (let i = 0; i < this.findResult.length; ++i) { | ||||
|                     const marker = this.findResult[i]; | ||||
|                 const findResult = this.findResult as Match[]; | ||||
|                 for (let i = 0; i < findResult.length; ++i) { | ||||
|                     const marker = findResult[i]; | ||||
|                     marker.clear(); | ||||
|                 } | ||||
|             }); | ||||
| @ -49,7 +68,7 @@ export default class FindInCode { | ||||
|             const re = new RegExp(wholeWordChar + searchTerm + wholeWordChar, "g" + (matchCase ? "" : "i")); | ||||
|             let curLine = 0; | ||||
|             let curChar = 0; | ||||
|             let curMatch = null; | ||||
|             let curMatch: RegExpExecArray | null = null; | ||||
|             findResult = []; | ||||
|             // All those markText take several seconds on e.g., this ~500-line
 | ||||
|             // script, batch them inside an operation, so they become
 | ||||
| @ -73,7 +92,7 @@ export default class FindInCode { | ||||
|                         let toPos = { line: curLine, ch: curChar + curMatch[0].length }; | ||||
|                         // or css = "color: #f3"
 | ||||
|                         let marker = doc.markText(fromPos, toPos, { className: FIND_RESULT_CSS_CLASSNAME }); | ||||
|                         findResult.push(marker); | ||||
|                         findResult?.push(marker); | ||||
| 
 | ||||
|                         // Set the first match beyond the cursor as the current match
 | ||||
|                         if (currentFound === -1) { | ||||
| @ -99,7 +118,7 @@ export default class FindInCode { | ||||
|         this.findResult = findResult; | ||||
| 
 | ||||
|         // Calculate curfound if not already, highlight it as selected
 | ||||
|         if (totalFound > 0) { | ||||
|         if (findResult && totalFound > 0) { | ||||
|             currentFound = Math.max(0, currentFound); | ||||
|             let marker = findResult[currentFound]; | ||||
|             let pos = marker.find(); | ||||
| @ -114,8 +133,12 @@ export default class FindInCode { | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     async findNext(direction, currentFound, nextFound) { | ||||
|     async findNext(direction: number, currentFound: number, nextFound: number) { | ||||
|         const codeEditor = await this.getCodeEditor(); | ||||
|         if (!codeEditor || !this.findResult) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         const doc = codeEditor.doc; | ||||
| 
 | ||||
|         //
 | ||||
| @ -137,18 +160,23 @@ export default class FindInCode { | ||||
|         codeEditor.scrollIntoView(pos.from); | ||||
|     } | ||||
| 
 | ||||
|     async findBoxClosed(totalFound, currentFound) { | ||||
|     async findBoxClosed(totalFound: number, currentFound: number) { | ||||
|         const codeEditor = await this.getCodeEditor(); | ||||
| 
 | ||||
|         if (totalFound > 0) { | ||||
|         if (codeEditor && totalFound > 0) { | ||||
|             const doc = codeEditor.doc; | ||||
|             const pos = this.findResult[currentFound].find(); | ||||
|             const pos = this.findResult?.[currentFound].find(); | ||||
|             // Note setting the selection sets the cursor to
 | ||||
|             // the end of the selection and scrolls it into
 | ||||
|             // view
 | ||||
|             if (pos) { | ||||
|                 doc.setSelection(pos.from, pos.to); | ||||
|             } | ||||
|             // Clear all markers
 | ||||
|             codeEditor.operation(() => { | ||||
|                 if (!this.findResult) { | ||||
|                     return; | ||||
|                 } | ||||
|                 for (let i = 0; i < this.findResult.length; ++i) { | ||||
|                     let marker = this.findResult[i]; | ||||
|                     marker.clear(); | ||||
| @ -157,9 +185,9 @@ export default class FindInCode { | ||||
|         } | ||||
|         this.findResult = null; | ||||
| 
 | ||||
|         codeEditor.focus(); | ||||
|         codeEditor?.focus(); | ||||
|     } | ||||
|     async replace(replaceText) { | ||||
|     async replace(replaceText: string) { | ||||
|         // this.findResult may be undefined and null
 | ||||
|         if (!this.findResult || this.findResult.length === 0) { | ||||
|             return; | ||||
| @ -178,8 +206,10 @@ export default class FindInCode { | ||||
|             let marker = this.findResult[currentFound]; | ||||
|             let pos = marker.find(); | ||||
|             const codeEditor = await this.getCodeEditor(); | ||||
|             const doc = codeEditor.doc; | ||||
|             const doc = codeEditor?.doc; | ||||
|             if (doc) { | ||||
|                 doc.replaceRange(replaceText, pos.from, pos.to); | ||||
|             } | ||||
|             marker.clear(); | ||||
| 
 | ||||
|             let nextFound; | ||||
| @ -194,17 +224,21 @@ export default class FindInCode { | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     async replaceAll(replaceText) { | ||||
|     async replaceAll(replaceText: string) { | ||||
|         if (!this.findResult || this.findResult.length === 0) { | ||||
|             return; | ||||
|         } | ||||
|         const codeEditor = await this.getCodeEditor(); | ||||
|         const doc = codeEditor.doc; | ||||
|         codeEditor.operation(() => { | ||||
|         const doc = codeEditor?.doc; | ||||
|         codeEditor?.operation(() => { | ||||
|             if (!this.findResult) { | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             for (let currentFound = 0; currentFound < this.findResult.length; currentFound++) { | ||||
|                 let marker = this.findResult[currentFound]; | ||||
|                 let pos = marker.find(); | ||||
|                 doc.replaceRange(replaceText, pos.from, pos.to); | ||||
|                 doc?.replaceRange(replaceText, pos.from, pos.to); | ||||
|                 marker.clear(); | ||||
|             } | ||||
|         }); | ||||
| @ -4,28 +4,33 @@ | ||||
| import libraryLoader from "../services/library_loader.js"; | ||||
| import utils from "../services/utils.js"; | ||||
| import appContext from "../components/app_context.js"; | ||||
| import type FindWidget from "./find.js"; | ||||
| 
 | ||||
| const FIND_RESULT_SELECTED_CSS_CLASSNAME = "ck-find-result_selected"; | ||||
| const FIND_RESULT_CSS_CLASSNAME = "ck-find-result"; | ||||
| 
 | ||||
| export default class FindInHtml { | ||||
|     constructor(parent) { | ||||
|         /** @property {FindWidget} */ | ||||
| 
 | ||||
|     private parent: FindWidget; | ||||
|     private currentIndex: number; | ||||
|     private $results: JQuery<HTMLElement> | null; | ||||
| 
 | ||||
|     constructor(parent: FindWidget) { | ||||
|         this.parent = parent; | ||||
|         this.currentIndex = 0; | ||||
|         this.$results = null; | ||||
|     } | ||||
| 
 | ||||
|     async performFind(searchTerm, matchCase, wholeWord) { | ||||
|     async performFind(searchTerm: string, matchCase: boolean, wholeWord: boolean) { | ||||
|         await libraryLoader.requireLibrary(libraryLoader.MARKJS); | ||||
| 
 | ||||
|         const $content = await this.parent.noteContext.getContentElement(); | ||||
|         const $content = await this.parent?.noteContext?.getContentElement(); | ||||
| 
 | ||||
|         const wholeWordChar = wholeWord ? "\\b" : ""; | ||||
|         const regExp = new RegExp(wholeWordChar + utils.escapeRegExp(searchTerm) + wholeWordChar, matchCase ? "g" : "gi"); | ||||
| 
 | ||||
|         return new Promise((res) => { | ||||
|             $content.unmark({ | ||||
|             $content?.unmark({ | ||||
|                 done: () => { | ||||
|                     $content.markRegExp(regExp, { | ||||
|                         element: "span", | ||||
| @ -48,8 +53,8 @@ export default class FindInHtml { | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     async findNext(direction, currentFound, nextFound) { | ||||
|         if (this.$results.length) { | ||||
|     async findNext(direction: -1 | 1, currentFound: number, nextFound: number) { | ||||
|         if (this.$results?.length) { | ||||
|             this.currentIndex += direction; | ||||
| 
 | ||||
|             if (this.currentIndex < 0) { | ||||
| @ -64,13 +69,15 @@ export default class FindInHtml { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async findBoxClosed(totalFound, currentFound) { | ||||
|         const $content = await this.parent.noteContext.getContentElement(); | ||||
|     async findBoxClosed(totalFound: number, currentFound: number) { | ||||
|         const $content = await this.parent?.noteContext?.getContentElement(); | ||||
|         if ($content) { | ||||
|             $content.unmark(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async jumpTo() { | ||||
|         if (this.$results.length) { | ||||
|         if (this.$results?.length) { | ||||
|             const offsetTop = 100; | ||||
|             const $current = this.$results.eq(this.currentIndex); | ||||
|             this.$results.removeClass(FIND_RESULT_SELECTED_CSS_CLASSNAME); | ||||
| @ -79,10 +86,11 @@ export default class FindInHtml { | ||||
|                 $current.addClass(FIND_RESULT_SELECTED_CSS_CLASSNAME); | ||||
|                 const position = $current.position().top - offsetTop; | ||||
| 
 | ||||
|                 const $content = await this.parent.noteContext.getContentElement(); | ||||
|                 const $contentWiget = appContext.getComponentByEl($content); | ||||
| 
 | ||||
|                 $contentWiget.triggerCommand("scrollContainerTo", { position }); | ||||
|                 const $content = await this.parent.noteContext?.getContentElement(); | ||||
|                 if ($content) { | ||||
|                     const $contentWidget = appContext.getComponentByEl($content[0]); | ||||
|                     $contentWidget.triggerCommand("scrollContainerTo", { position }); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @ -1,14 +1,29 @@ | ||||
| import type FindWidget from "./find.js"; | ||||
| 
 | ||||
| // TODO: Deduplicate.
 | ||||
| interface Match { | ||||
|     className: string; | ||||
|     clear(): void; | ||||
|     find(): { | ||||
|         from: number; | ||||
|         to: number; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| export default class FindInText { | ||||
|     constructor(parent) { | ||||
|         /** @property {FindWidget} */ | ||||
| 
 | ||||
|     private parent: FindWidget; | ||||
|     private findResult?: Match[] | null; | ||||
| 
 | ||||
|     constructor(parent: FindWidget) { | ||||
|         this.parent = parent; | ||||
|     } | ||||
| 
 | ||||
|     async getTextEditor() { | ||||
|         return this.parent.noteContext.getTextEditor(); | ||||
|         return this.parent?.noteContext?.getTextEditor(); | ||||
|     } | ||||
| 
 | ||||
|     async performFind(searchTerm, matchCase, wholeWord) { | ||||
|     async performFind(searchTerm: string, matchCase: boolean, wholeWord: boolean) { | ||||
|         // Do this even if the searchTerm is empty so the markers are cleared and
 | ||||
|         // the counters updated
 | ||||
|         const textEditor = await this.getTextEditor(); | ||||
| @ -54,7 +69,7 @@ export default class FindInText { | ||||
|             // XXX Do this accessing the private data?
 | ||||
|             // See https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/findnextcommand.js
 | ||||
|             for (let i = 0; i < currentFound; ++i) { | ||||
|                 textEditor.execute("findNext", searchTerm); | ||||
|                 textEditor?.execute("findNext", searchTerm); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| @ -64,7 +79,7 @@ export default class FindInText { | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     async findNext(direction, currentFound, nextFound) { | ||||
|     async findNext(direction: number, currentFound: number, nextFound: number) { | ||||
|         const textEditor = await this.getTextEditor(); | ||||
| 
 | ||||
|         // There are no parameters for findNext/findPrev
 | ||||
| @ -72,20 +87,23 @@ export default class FindInText { | ||||
|         // curFound wrap around above assumes findNext and
 | ||||
|         // findPrevious wraparound, which is what they do
 | ||||
|         if (direction > 0) { | ||||
|             textEditor.execute("findNext"); | ||||
|             textEditor?.execute("findNext"); | ||||
|         } else { | ||||
|             textEditor.execute("findPrevious"); | ||||
|             textEditor?.execute("findPrevious"); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async findBoxClosed(totalFound, currentFound) { | ||||
|     async findBoxClosed(totalFound: number, currentFound: number) { | ||||
|         const textEditor = await this.getTextEditor(); | ||||
|         if (!textEditor) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (totalFound > 0) { | ||||
|             // Clear the markers and set the caret to the
 | ||||
|             // current occurrence
 | ||||
|             const model = textEditor.model; | ||||
|             const range = this.findResult.results.get(currentFound).marker.getRange(); | ||||
|             const range = this.findResult?.results?.get(currentFound).marker.getRange(); | ||||
|             // From
 | ||||
|             // https://github.com/ckeditor/ckeditor5/blob/b95e2faf817262ac0e1e21993d9c0bde3f1be594/packages/ckeditor5-find-and-replace/src/findandreplace.js#L92
 | ||||
|             // XXX Roll our own since already done for codeEditor and
 | ||||
| @ -104,17 +122,17 @@ export default class FindInText { | ||||
|         textEditor.focus(); | ||||
|     } | ||||
| 
 | ||||
|     async replace(replaceText) { | ||||
|     async replace(replaceText: string) { | ||||
|         if (this.editingState !== undefined && this.editingState.highlightedResult !== null) { | ||||
|             const textEditor = await this.getTextEditor(); | ||||
|             textEditor.execute("replace", replaceText, this.editingState.highlightedResult); | ||||
|             textEditor?.execute("replace", replaceText, this.editingState.highlightedResult); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async replaceAll(replaceText) { | ||||
|     async replaceAll(replaceText: string) { | ||||
|         if (this.editingState !== undefined && this.editingState.results.length > 0) { | ||||
|             const textEditor = await this.getTextEditor(); | ||||
|             textEditor.execute("replaceAll", replaceText, this.editingState.results); | ||||
|             textEditor?.execute("replaceAll", replaceText, this.editingState.results); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -5,10 +5,9 @@ import type NoteContext from "../components/note_context.js"; | ||||
| 
 | ||||
| /** | ||||
|  * This widget allows for changing and updating depending on the active note. | ||||
|  * @extends {BasicWidget} | ||||
|  */ | ||||
| class NoteContextAwareWidget extends BasicWidget { | ||||
|     protected noteContext?: NoteContext; | ||||
|     noteContext?: NoteContext; | ||||
| 
 | ||||
|     isNoteContext(ntxId: string | string[] | null | undefined) { | ||||
|         if (Array.isArray(ntxId)) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Elian Doran
						Elian Doran