Skip to content

Commit 5493819

Browse files
committed
Extract SimpleEditor to a new file
1 parent a4f8d86 commit 5493819

File tree

2 files changed

+108
-100
lines changed

2 files changed

+108
-100
lines changed

ui/frontend/editor/Editor.tsx

Lines changed: 2 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -5,111 +5,13 @@ import * as actions from '../actions';
55
import { useAppDispatch } from '../configureStore';
66

77
import AceEditor from './AceEditor';
8+
import SimpleEditor from './SimpleEditor';
89
import MonacoEditor from './MonacoEditor';
9-
import { CommonEditorProps, Editor as EditorType, Position, Selection } from '../types';
10+
import { Editor as EditorType } from '../types';
1011
import { State } from '../reducers';
1112

1213
import styles from './Editor.module.css';
1314

14-
class CodeByteOffsets {
15-
readonly code: string;
16-
readonly lines: string[];
17-
18-
constructor(code: string) {
19-
this.code = code;
20-
this.lines = code.split('\n');
21-
}
22-
23-
public lineToOffsets(line: number) {
24-
const precedingBytes = this.bytesBeforeLine(line);
25-
26-
const highlightedLine = this.lines[line];
27-
const highlightedBytes = highlightedLine.length;
28-
29-
return [precedingBytes, precedingBytes + highlightedBytes];
30-
}
31-
32-
public rangeToOffsets(start: Position, end: Position) {
33-
const startBytes = this.positionToBytes(start);
34-
const endBytes = this.positionToBytes(end);
35-
return [startBytes, endBytes];
36-
}
37-
38-
private positionToBytes(position: Position) {
39-
// Subtract one as this logic is zero-based and the columns are one-based
40-
return this.bytesBeforeLine(position.line) + position.column - 1;
41-
}
42-
43-
private bytesBeforeLine(line: number) {
44-
// Subtract one as this logic is zero-based and the lines are one-based
45-
line -= 1;
46-
47-
const precedingLines = this.lines.slice(0, line);
48-
49-
// Add one to account for the newline we split on and removed
50-
return precedingLines.map(l => l.length + 1).reduce((a, b) => a + b);
51-
}
52-
}
53-
54-
class SimpleEditor extends React.PureComponent<CommonEditorProps> {
55-
private _editor: HTMLTextAreaElement | null = null;
56-
57-
private onChange: React.ChangeEventHandler<HTMLTextAreaElement> = e => this.props.onEditCode(e.target.value);
58-
private trackEditor: React.RefCallback<HTMLTextAreaElement> = component => this._editor = component;
59-
private onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = e => {
60-
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
61-
this.props.execute();
62-
}
63-
}
64-
65-
public render() {
66-
return (
67-
<textarea
68-
ref={this.trackEditor}
69-
className={styles.simple}
70-
name="editor-simple"
71-
autoCapitalize="none"
72-
autoComplete="off"
73-
autoCorrect="off"
74-
spellCheck={false}
75-
value={this.props.code}
76-
onChange={this.onChange}
77-
onKeyDown={this.onKeyDown} />
78-
);
79-
}
80-
81-
public componentDidUpdate(prevProps: CommonEditorProps) {
82-
this.gotoPosition(prevProps.position, this.props.position);
83-
this.setSelection(prevProps.selection, this.props.selection);
84-
}
85-
86-
private gotoPosition(oldPosition: Position, newPosition: Position) {
87-
const editor = this._editor;
88-
89-
if (!newPosition || !editor) { return; }
90-
if (newPosition === oldPosition) { return; }
91-
92-
const offsets = new CodeByteOffsets(this.props.code);
93-
const [startBytes, endBytes] = offsets.lineToOffsets(newPosition.line);
94-
95-
editor.focus();
96-
editor.setSelectionRange(startBytes, endBytes);
97-
}
98-
99-
private setSelection(oldSelection: Selection, newSelection: Selection) {
100-
const editor = this._editor;
101-
102-
if (!newSelection || !newSelection.start || !newSelection.end || !editor) { return; }
103-
if (newSelection === oldSelection) { return; }
104-
105-
const offsets = new CodeByteOffsets(this.props.code);
106-
const [startBytes, endBytes] = offsets.rangeToOffsets(newSelection.start, newSelection.end);
107-
108-
editor.focus();
109-
editor.setSelectionRange(startBytes, endBytes);
110-
}
111-
}
112-
11315
const editorMap = {
11416
[EditorType.Simple]: SimpleEditor,
11517
[EditorType.Ace]: AceEditor,

ui/frontend/editor/SimpleEditor.tsx

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import React from 'react';
2+
3+
import { CommonEditorProps, Position, Selection } from '../types';
4+
5+
import styles from './Editor.module.css';
6+
7+
class CodeByteOffsets {
8+
readonly code: string;
9+
readonly lines: string[];
10+
11+
constructor(code: string) {
12+
this.code = code;
13+
this.lines = code.split('\n');
14+
}
15+
16+
public lineToOffsets(line: number) {
17+
const precedingBytes = this.bytesBeforeLine(line);
18+
19+
const highlightedLine = this.lines[line];
20+
const highlightedBytes = highlightedLine.length;
21+
22+
return [precedingBytes, precedingBytes + highlightedBytes];
23+
}
24+
25+
public rangeToOffsets(start: Position, end: Position) {
26+
const startBytes = this.positionToBytes(start);
27+
const endBytes = this.positionToBytes(end);
28+
return [startBytes, endBytes];
29+
}
30+
31+
private positionToBytes(position: Position) {
32+
// Subtract one as this logic is zero-based and the columns are one-based
33+
return this.bytesBeforeLine(position.line) + position.column - 1;
34+
}
35+
36+
private bytesBeforeLine(line: number) {
37+
// Subtract one as this logic is zero-based and the lines are one-based
38+
line -= 1;
39+
40+
const precedingLines = this.lines.slice(0, line);
41+
42+
// Add one to account for the newline we split on and removed
43+
return precedingLines.map(l => l.length + 1).reduce((a, b) => a + b);
44+
}
45+
}
46+
47+
class SimpleEditor extends React.PureComponent<CommonEditorProps> {
48+
private _editor: HTMLTextAreaElement | null = null;
49+
50+
private onChange: React.ChangeEventHandler<HTMLTextAreaElement> = e => this.props.onEditCode(e.target.value);
51+
private trackEditor: React.RefCallback<HTMLTextAreaElement> = component => this._editor = component;
52+
private onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = e => {
53+
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
54+
this.props.execute();
55+
}
56+
}
57+
58+
public render() {
59+
return (
60+
<textarea
61+
ref={this.trackEditor}
62+
className={styles.simple}
63+
name="editor-simple"
64+
autoCapitalize="none"
65+
autoComplete="off"
66+
autoCorrect="off"
67+
spellCheck={false}
68+
value={this.props.code}
69+
onChange={this.onChange}
70+
onKeyDown={this.onKeyDown} />
71+
);
72+
}
73+
74+
public componentDidUpdate(prevProps: CommonEditorProps) {
75+
this.gotoPosition(prevProps.position, this.props.position);
76+
this.setSelection(prevProps.selection, this.props.selection);
77+
}
78+
79+
private gotoPosition(oldPosition: Position, newPosition: Position) {
80+
const editor = this._editor;
81+
82+
if (!newPosition || !editor) { return; }
83+
if (newPosition === oldPosition) { return; }
84+
85+
const offsets = new CodeByteOffsets(this.props.code);
86+
const [startBytes, endBytes] = offsets.lineToOffsets(newPosition.line);
87+
88+
editor.focus();
89+
editor.setSelectionRange(startBytes, endBytes);
90+
}
91+
92+
private setSelection(oldSelection: Selection, newSelection: Selection) {
93+
const editor = this._editor;
94+
95+
if (!newSelection || !newSelection.start || !newSelection.end || !editor) { return; }
96+
if (newSelection === oldSelection) { return; }
97+
98+
const offsets = new CodeByteOffsets(this.props.code);
99+
const [startBytes, endBytes] = offsets.rangeToOffsets(newSelection.start, newSelection.end);
100+
101+
editor.focus();
102+
editor.setSelectionRange(startBytes, endBytes);
103+
}
104+
}
105+
106+
export default SimpleEditor;

0 commit comments

Comments
 (0)