Skip to content

Commit 693bf9f

Browse files
committed
Extract SimpleEditor to a new file
1 parent 98e5998 commit 693bf9f

File tree

4 files changed

+121
-101
lines changed

4 files changed

+121
-101
lines changed

ui/frontend/.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ module.exports = {
6060
},
6161
overrides: [
6262
{
63-
files: ['.eslintrc.js', 'websocketMiddleware.ts'],
63+
files: ['.eslintrc.js', 'editor/SimpleEditor.tsx', 'websocketMiddleware.ts'],
6464
extends: ['prettier'],
6565
},
6666
],

ui/frontend/.prettierignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ node_modules
1111

1212
# Slowly migrate files that we've touched
1313
!.eslintrc.js
14+
!editor/SimpleEditor.tsx
1415
!websocketMiddleware.ts

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: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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) =>
51+
this.props.onEditCode(e.target.value);
52+
private trackEditor: React.RefCallback<HTMLTextAreaElement> = (component) =>
53+
(this._editor = component);
54+
private onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = (e) => {
55+
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
56+
this.props.execute();
57+
}
58+
};
59+
60+
public render() {
61+
return (
62+
<textarea
63+
ref={this.trackEditor}
64+
className={styles.simple}
65+
name="editor-simple"
66+
autoCapitalize="none"
67+
autoComplete="off"
68+
autoCorrect="off"
69+
spellCheck={false}
70+
value={this.props.code}
71+
onChange={this.onChange}
72+
onKeyDown={this.onKeyDown}
73+
/>
74+
);
75+
}
76+
77+
public componentDidUpdate(prevProps: CommonEditorProps) {
78+
this.gotoPosition(prevProps.position, this.props.position);
79+
this.setSelection(prevProps.selection, this.props.selection);
80+
}
81+
82+
private gotoPosition(oldPosition: Position, newPosition: Position) {
83+
const editor = this._editor;
84+
85+
if (!newPosition || !editor) {
86+
return;
87+
}
88+
if (newPosition === oldPosition) {
89+
return;
90+
}
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) {
103+
return;
104+
}
105+
if (newSelection === oldSelection) {
106+
return;
107+
}
108+
109+
const offsets = new CodeByteOffsets(this.props.code);
110+
const [startBytes, endBytes] = offsets.rangeToOffsets(newSelection.start, newSelection.end);
111+
112+
editor.focus();
113+
editor.setSelectionRange(startBytes, endBytes);
114+
}
115+
}
116+
117+
export default SimpleEditor;

0 commit comments

Comments
 (0)