You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Merge pull request #9559 from personalizedrefrigerator/pr/merge-release-2-13
Chore: Merge release 2.13
This commit is contained in:
		| @@ -578,6 +578,7 @@ packages/editor/CodeMirror/editorCommands/swapLine.js | ||||
| packages/editor/CodeMirror/getScrollFraction.js | ||||
| packages/editor/CodeMirror/markdown/computeSelectionFormatting.test.js | ||||
| packages/editor/CodeMirror/markdown/computeSelectionFormatting.js | ||||
| packages/editor/CodeMirror/markdown/decoratorExtension.test.js | ||||
| packages/editor/CodeMirror/markdown/decoratorExtension.js | ||||
| packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.js | ||||
| packages/editor/CodeMirror/markdown/markdownCommands.test.js | ||||
|   | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -558,6 +558,7 @@ packages/editor/CodeMirror/editorCommands/swapLine.js | ||||
| packages/editor/CodeMirror/getScrollFraction.js | ||||
| packages/editor/CodeMirror/markdown/computeSelectionFormatting.test.js | ||||
| packages/editor/CodeMirror/markdown/computeSelectionFormatting.js | ||||
| packages/editor/CodeMirror/markdown/decoratorExtension.test.js | ||||
| packages/editor/CodeMirror/markdown/decoratorExtension.js | ||||
| packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.js | ||||
| packages/editor/CodeMirror/markdown/markdownCommands.test.js | ||||
|   | ||||
| @@ -276,6 +276,7 @@ function NoteEditor(props: Props, ref: any) { | ||||
|  | ||||
| 	const setInitialSelectionJS = props.initialSelection ? ` | ||||
| 		cm.select(${props.initialSelection.start}, ${props.initialSelection.end}); | ||||
| 		cm.execCommand('scrollSelectionIntoView'); | ||||
| 	` : ''; | ||||
|  | ||||
| 	const editorSettings: EditorSettings = { | ||||
| @@ -337,6 +338,7 @@ function NoteEditor(props: Props, ref: any) { | ||||
| 				const settings = ${JSON.stringify(editorSettings)}; | ||||
|  | ||||
| 				cm = codeMirrorBundle.initCodeMirror(parentElement, initialText, settings); | ||||
|  | ||||
| 				${setInitialSelectionJS} | ||||
|  | ||||
| 				window.onresize = () => { | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import NoteEditor from '../NoteEditor/NoteEditor'; | ||||
| import { Size } from '@joplin/utils/types'; | ||||
| const FileViewer = require('react-native-file-viewer').default; | ||||
| const React = require('react'); | ||||
| import { Keyboard, View, TextInput, StyleSheet, Linking, Image, Share } from 'react-native'; | ||||
| import { Keyboard, View, TextInput, StyleSheet, Linking, Image, Share, NativeSyntheticEvent } from 'react-native'; | ||||
| import { Platform, PermissionsAndroid } from 'react-native'; | ||||
| const { connect } = require('react-redux'); | ||||
| // const { MarkdownEditor } = require('@joplin/lib/../MarkdownEditor/index.js'); | ||||
| @@ -52,10 +52,11 @@ import isEditableResource from '../NoteEditor/ImageEditor/isEditableResource'; | ||||
| import VoiceTypingDialog from '../voiceTyping/VoiceTypingDialog'; | ||||
| import { voskEnabled } from '../../services/voiceTyping/vosk'; | ||||
| import { isSupportedLanguage } from '../../services/voiceTyping/vosk.android'; | ||||
| import { ChangeEvent as EditorChangeEvent, UndoRedoDepthChangeEvent } from '@joplin/editor/events'; | ||||
| import { ChangeEvent as EditorChangeEvent, SelectionRangeChangeEvent, UndoRedoDepthChangeEvent } from '@joplin/editor/events'; | ||||
| import { join } from 'path'; | ||||
| import { Dispatch } from 'redux'; | ||||
| import { RefObject } from 'react'; | ||||
| import { SelectionRange } from '../NoteEditor/types'; | ||||
| const urlUtils = require('@joplin/lib/urlUtils'); | ||||
|  | ||||
| const emptyArray: any[] = []; | ||||
| @@ -177,7 +178,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B | ||||
| 	private noteTagDialog_closeRequested: any; | ||||
| 	private onJoplinLinkClick_: any; | ||||
| 	private refreshResource: (resource: any, noteBody?: string)=> Promise<void>; | ||||
| 	private selection: any; | ||||
| 	private selection: SelectionRange; | ||||
| 	private menuOptionsCache_: Record<string, any>; | ||||
| 	private focusUpdateIID_: any; | ||||
| 	private folderPickerOptions_: any; | ||||
| @@ -371,7 +372,6 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B | ||||
| 		this.undoRedoService_stackChange = this.undoRedoService_stackChange.bind(this); | ||||
| 		this.screenHeader_undoButtonPress = this.screenHeader_undoButtonPress.bind(this); | ||||
| 		this.screenHeader_redoButtonPress = this.screenHeader_redoButtonPress.bind(this); | ||||
| 		this.body_selectionChange = this.body_selectionChange.bind(this); | ||||
| 		this.onBodyViewerLoadEnd = this.onBodyViewerLoadEnd.bind(this); | ||||
| 		this.onBodyViewerCheckboxChange = this.onBodyViewerCheckboxChange.bind(this); | ||||
| 		this.onBodyChange = this.onBodyChange.bind(this); | ||||
| @@ -640,13 +640,13 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B | ||||
| 		this.scheduleSave(); | ||||
| 	} | ||||
|  | ||||
| 	private body_selectionChange(event: any) { | ||||
| 		if (this.useEditorBeta()) { | ||||
| 			this.selection = event.selection; | ||||
| 		} else { | ||||
| 			this.selection = event.nativeEvent.selection; | ||||
| 		} | ||||
| 	} | ||||
| 	private onPlainEdtiorSelectionChange = (event: NativeSyntheticEvent<any>) => { | ||||
| 		this.selection = event.nativeEvent.selection; | ||||
| 	}; | ||||
|  | ||||
| 	private onMarkdownEditorSelectionChange = (event: SelectionRangeChangeEvent) => { | ||||
| 		this.selection = { start: event.from, end: event.to }; | ||||
| 	}; | ||||
|  | ||||
| 	public makeSaveAction() { | ||||
| 		return async () => { | ||||
| @@ -1508,7 +1508,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B | ||||
| 						multiline={true} | ||||
| 						value={note.body} | ||||
| 						onChangeText={(text: string) => this.body_changeText(text)} | ||||
| 						onSelectionChange={this.body_selectionChange} | ||||
| 						onSelectionChange={this.onPlainEdtiorSelectionChange} | ||||
| 						blurOnSubmit={false} | ||||
| 						selectionColor={theme.textSelectionColor} | ||||
| 						keyboardAppearance={theme.keyboardAppearance} | ||||
| @@ -1530,7 +1530,7 @@ class NoteScreenComponent extends BaseScreenComponent<Props, State> implements B | ||||
| 					initialText={note.body} | ||||
| 					initialSelection={this.selection} | ||||
| 					onChange={this.onBodyChange} | ||||
| 					onSelectionChange={this.body_selectionChange} | ||||
| 					onSelectionChange={this.onMarkdownEditorSelectionChange} | ||||
| 					onUndoRedoDepthChange={this.onUndoRedoDepthChange} | ||||
| 					onAttach={() => this.showAttachMenu()} | ||||
| 					readOnly={this.state.readOnly} | ||||
|   | ||||
| @@ -0,0 +1,30 @@ | ||||
| import { EditorSelection } from '@codemirror/state'; | ||||
| import createTestEditor from '../testUtil/createTestEditor'; | ||||
| import decoratorExtension from './decoratorExtension'; | ||||
|  | ||||
| jest.retryTimes(2); | ||||
|  | ||||
| describe('decoratorExtension', () => { | ||||
| 	it('should highlight code blocks within tables', async () => { | ||||
| 		// Regression test for https://github.com/laurent22/joplin/issues/9477 | ||||
| 		const editorText = ` | ||||
| left    | right | ||||
| --------|------- | ||||
| \`foo\` | bar   | ||||
| 		`; | ||||
| 		const editor = await createTestEditor( | ||||
| 			editorText, | ||||
|  | ||||
| 			// Put the initial cursor at the start of "foo" | ||||
| 			EditorSelection.cursor(editorText.indexOf('foo')), | ||||
|  | ||||
| 			['TableRow', 'InlineCode'], | ||||
| 			[decoratorExtension], | ||||
| 		); | ||||
|  | ||||
| 		const codeBlock = editor.contentDOM.querySelector('.cm-inlineCode'); | ||||
|  | ||||
| 		expect(codeBlock.textContent).toBe('`foo`'); | ||||
| 		expect(codeBlock.parentElement.classList.contains('.cm-tableRow')); | ||||
| 	}); | ||||
| }); | ||||
| @@ -123,7 +123,7 @@ const nodeNameToMarkDecoration: Record<string, Decoration> = { | ||||
| }; | ||||
|  | ||||
|  | ||||
| type DecorationDescription = { pos: number; length?: number; decoration: Decoration }; | ||||
| type DecorationDescription = { pos: number; length: number; decoration: Decoration }; | ||||
|  | ||||
| // Returns a set of [Decoration]s, associated with block syntax groups that require | ||||
| // full-line styling. | ||||
| @@ -138,6 +138,7 @@ const computeDecorations = (view: EditorView) => { | ||||
| 			const line = view.state.doc.lineAt(pos); | ||||
| 			decorations.push({ | ||||
| 				pos: line.from, | ||||
| 				length: 0, | ||||
| 				decoration, | ||||
| 			}); | ||||
|  | ||||
| @@ -193,13 +194,23 @@ const computeDecorations = (view: EditorView) => { | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	decorations.sort((a, b) => a.pos - b.pos); | ||||
| 	// Decorations need to be sorted in ascending order first by start position, | ||||
| 	// then by length. Adding items to the RangeSetBuilder in an incorrect order | ||||
| 	// causes an exception to be thrown. | ||||
| 	decorations.sort((a, b) => { | ||||
| 		const posComparison = a.pos - b.pos; | ||||
| 		if (posComparison !== 0) { | ||||
| 			return posComparison; | ||||
| 		} | ||||
|  | ||||
| 		const lengthComparison = a.length - b.length; | ||||
| 		return lengthComparison; | ||||
| 	}); | ||||
|  | ||||
| 	// Items need to be added to a RangeSetBuilder in ascending order | ||||
| 	const decorationBuilder = new RangeSetBuilder<Decoration>(); | ||||
| 	for (const { pos, length, decoration } of decorations) { | ||||
| 		// Null length => entire line | ||||
| 		decorationBuilder.add(pos, pos + (length ?? 0), decoration); | ||||
| 		// Zero length => entire line | ||||
| 		decorationBuilder.add(pos, pos + length, decoration); | ||||
| 	} | ||||
| 	return decorationBuilder.finish(); | ||||
| }; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { markdown } from '@codemirror/lang-markdown'; | ||||
| import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown'; | ||||
| import { indentUnit, syntaxTree } from '@codemirror/language'; | ||||
| import { SelectionRange, EditorSelection, EditorState } from '@codemirror/state'; | ||||
| import { SelectionRange, EditorSelection, EditorState, Extension } from '@codemirror/state'; | ||||
| import { EditorView } from '@codemirror/view'; | ||||
| import { MarkdownMathExtension } from '../markdown/markdownMathParser'; | ||||
| import forceFullParse from './forceFullParse'; | ||||
| @@ -10,7 +10,10 @@ import loadLangauges from './loadLanguages'; | ||||
| // Creates and returns a minimal editor with markdown extensions. Waits to return the editor | ||||
| // until all syntax tree tags in `expectedSyntaxTreeTags` exist. | ||||
| const createTestEditor = async ( | ||||
| 	initialText: string, initialSelection: SelectionRange, expectedSyntaxTreeTags: string[], | ||||
| 	initialText: string, | ||||
| 	initialSelection: SelectionRange, | ||||
| 	expectedSyntaxTreeTags: string[], | ||||
| 	extraExtensions: Extension[] = [], | ||||
| ): Promise<EditorView> => { | ||||
| 	await loadLangauges(); | ||||
|  | ||||
| @@ -23,6 +26,7 @@ const createTestEditor = async ( | ||||
| 			}), | ||||
| 			indentUnit.of('\t'), | ||||
| 			EditorState.tabSize.of(4), | ||||
| 			extraExtensions, | ||||
| 		], | ||||
| 	}); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user