Mobile: Fixes #6324: Support inserting attachments from Beta Editor (#6325)

pull/6385/head
Henry Heino 2022-04-11 03:56:45 -07:00 committed by GitHub
parent cffea3ea1e
commit 5962b0813e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 9 deletions

View File

@ -19,6 +19,8 @@ interface CodeMirrorResult {
editor: EditorView;
undo: Function;
redo: Function;
select: (anchor: number, head: number)=> void;
insertText: (text: string)=> void;
}
function postMessage(name: string, data: any) {
@ -180,6 +182,13 @@ export function initCodeMirror(parentElement: any, initialText: string, theme: a
postMessage('onChange', { value: editor.state.doc.toString() });
schedulePostUndoRedoDepthChange(editor);
}
if (!viewUpdate.state.selection.eq(viewUpdate.startState.selection)) {
const mainRange = viewUpdate.state.selection.main;
const selStart = mainRange.from;
const selEnd = mainRange.to;
postMessage('onSelectionChange', { selection: { start: selStart, end: selEnd } });
}
}),
],
doc: initialText,
@ -197,5 +206,14 @@ export function initCodeMirror(parentElement: any, initialText: string, theme: a
redo(editor);
schedulePostUndoRedoDepthChange(editor, true);
},
select: (anchor: number, head: number) => {
editor.dispatch(editor.state.update({
selection: { anchor, head },
scrollIntoView: true,
}));
},
insertText: (text: string) => {
editor.dispatch(editor.state.replaceSelection(text));
},
};
}

View File

@ -15,14 +15,27 @@ export interface UndoRedoDepthChangeEvent {
redoDepth: number;
}
export interface Selection {
start: number;
end: number;
}
export interface SelectionChangeEvent {
selection: Selection;
}
type ChangeEventHandler = (event: ChangeEvent)=> void;
type UndoRedoDepthChangeHandler = (event: UndoRedoDepthChangeEvent)=> void;
type SelectionChangeEventHandler = (event: SelectionChangeEvent)=> void;
interface Props {
themeId: number;
initialText: string;
initialSelection?: Selection;
style: any;
onChange: ChangeEventHandler;
onSelectionChange: SelectionChangeEventHandler;
onUndoRedoDepthChange: UndoRedoDepthChangeHandler;
}
@ -212,11 +225,15 @@ function NoteEditor(props: Props, ref: any) {
const [source, setSource] = useState(undefined);
const webviewRef = useRef(null);
const setInitialSelectionJS = props.initialSelection ? `
cm.select(${props.initialSelection.start}, ${props.initialSelection.end});
` : '';
const injectedJavaScript = `
function postMessage(name, data) {
window.ReactNativeWebView.postMessage(JSON.stringify({
data,
name,
name,
}));
}
@ -227,7 +244,7 @@ function NoteEditor(props: Props, ref: any) {
// This variable is not used within this script
// but is called using "injectJavaScript" from
// the wrapper component.
let cm = null;
window.cm = null;
try {
${shim.injectedJs('codeMirrorBundle')};
@ -237,6 +254,7 @@ function NoteEditor(props: Props, ref: any) {
const initialText = ${JSON.stringify(props.initialText)};
cm = codeMirrorBundle.initCodeMirror(parentElement, initialText, theme);
${setInitialSelectionJS}
} catch (e) {
window.ReactNativeWebView.postMessage("error:" + e.message + ": " + JSON.stringify(e))
} finally {
@ -255,6 +273,14 @@ function NoteEditor(props: Props, ref: any) {
redo: function() {
webviewRef.current.injectJavaScript('cm.redo(); true;');
},
select: (anchor: number, head: number) => {
webviewRef.current.injectJavaScript(
`cm.select(${JSON.stringify(anchor)}, ${JSON.stringify(head)}); true;`
);
},
insertText: (text: string) => {
webviewRef.current.injectJavaScript(`cm.insertText(${JSON.stringify(text)}); true;`);
},
};
});
@ -301,6 +327,10 @@ function NoteEditor(props: Props, ref: any) {
console.info('onUndoRedoDepthChange', event);
props.onUndoRedoDepthChange(event);
},
onSelectionChange: (event: SelectionChangeEvent) => {
props.onSelectionChange(event);
},
};
if (handlers[msg.name]) {

View File

@ -488,7 +488,11 @@ class NoteScreenComponent extends BaseScreenComponent {
}
body_selectionChange(event: any) {
this.selection = event.nativeEvent.selection;
if (this.useEditorBeta()) {
this.selection = event.selection;
} else {
this.selection = event.nativeEvent.selection;
}
}
makeSaveAction() {
@ -708,9 +712,17 @@ class NoteScreenComponent extends BaseScreenComponent {
const newNote = Object.assign({}, this.state.note);
if (this.state.mode == 'edit' && !!this.selection) {
const newText = `\n${resourceTag}\n`;
const prefix = newNote.body.substring(0, this.selection.start);
const suffix = newNote.body.substring(this.selection.end);
newNote.body = `${prefix}\n${resourceTag}\n${suffix}`;
newNote.body = `${prefix}${newText}${suffix}`;
if (this.useEditorBeta()) {
// The beta editor needs to be explicitly informed of changes
// to the note's body
this.editorRef.current.insertText(newText);
}
} else {
newNote.body += `\n${resourceTag}`;
}
@ -879,11 +891,6 @@ class NoteScreenComponent extends BaseScreenComponent {
output.push({
title: _('Attach...'),
onPress: async () => {
if (this.state.mode === 'edit' && this.useEditorBeta()) {
alert('Attaching files from the beta editor is not yet supported. You may do so from the viewer mode instead.');
return;
}
const buttons = [];
// On iOS, it will show "local files", which means certain files saved from the browser
@ -1125,7 +1132,9 @@ class NoteScreenComponent extends BaseScreenComponent {
ref={this.editorRef}
themeId={this.props.themeId}
initialText={note.body}
initialSelection={this.selection}
onChange={this.onBodyChange}
onSelectionChange={this.body_selectionChange}
onUndoRedoDepthChange={this.onUndoRedoDepthChange}
style={this.styles().bodyTextInput}
/>;