refactor: minor clean up of editor (#43513)

This commit is contained in:
Oliver Eyton-Williams
2021-09-21 14:35:12 +02:00
committed by GitHub
parent bfb70e422e
commit 222fc3f255
2 changed files with 37 additions and 63 deletions

View File

@ -35,10 +35,6 @@
color: var(--secondary-background);
}
/* [widgetid='my.overlay.widget'] {
padding: 10px;
} */
.editor-upper-jaw,
.editor-lower-jaw {
padding: 15px 15px 15px 0px;

View File

@ -74,16 +74,16 @@ interface EditorProps {
interface EditorProperties {
editor?: editor.IStandaloneCodeEditor;
model?: editor.ITextModel;
viewZoneId: string;
descriptionZoneId: string;
startEditDecId: string;
endEditDecId: string;
insideEditDecId: string;
viewZoneHeight: number;
descriptionZoneHeight: number;
outputZoneHeight: number;
outputZoneId: string;
descriptionNode?: HTMLDivElement;
outputNode?: HTMLDivElement;
overlayWidget?: editor.IOverlayWidget;
descriptionWidget?: editor.IOverlayWidget;
outputWidget?: editor.IOverlayWidget;
}
@ -174,11 +174,11 @@ const toLastLine = (range: RangeType) => {
// TODO: properly initialise data with values not null
const initialData: EditorProperties = {
viewZoneId: '',
descriptionZoneId: '',
startEditDecId: '',
endEditDecId: '',
insideEditDecId: '',
viewZoneHeight: 0,
descriptionZoneHeight: 0,
outputZoneId: '',
outputZoneHeight: 0
};
@ -207,8 +207,6 @@ const Editor = (props: EditorProps): JSX.Element => {
// automatically be first, but if there's jsx and js (for some reason) it
// will be [jsx, js].
// NOTE: the ARIA state is controlled by fileKey, so changes to it must
// trigger a re-render. Hence state:
const options: editor.IStandaloneEditorConstructionOptions = {
fontSize: 18,
scrollBeyondLastLine: false,
@ -400,99 +398,89 @@ const Editor = (props: EditorProps): JSX.Element => {
};
};
const domNode = createDescription(editor);
const descriptionNode = createDescription(editor);
const outputNode = createOutputNode(editor);
const overlayWidget = createWidget(
'my.overlay.widget',
domNode,
getViewZoneTop
const descriptionWidget = createWidget(
'description.widget',
descriptionNode,
getDescriptionZoneTop
);
data.overlayWidget = overlayWidget;
data.descriptionWidget = descriptionWidget;
const outputWidget = createWidget(
'my.output.widget',
'output.widget',
outputNode,
getOutputZoneTop
);
data.outputWidget = outputWidget;
editor.addOverlayWidget(overlayWidget);
editor.addOverlayWidget(descriptionWidget);
// TODO: order of insertion into the DOM probably matters, revisit once
// the tabs have been fixed!
editor.addOverlayWidget(outputWidget);
editor.changeViewZones(viewZoneCallback);
editor.changeViewZones(descriptionZoneCallback);
editor.changeViewZones(outputZoneCallback);
editor.onDidScrollChange(() => {
editor.layoutOverlayWidget(overlayWidget);
editor.layoutOverlayWidget(descriptionWidget);
editor.layoutOverlayWidget(outputWidget);
});
showEditableRegion(editableBoundaries);
}
};
const viewZoneCallback = (changeAccessor: editor.IViewZoneChangeAccessor) => {
const descriptionZoneCallback = (
changeAccessor: editor.IViewZoneChangeAccessor
) => {
const editor = data.editor;
if (!editor) return;
// TODO: is there any point creating this here? I know it's cached, but
// would it not be better just sourced from the overlayWidget?
const domNode = createDescription(editor);
// make sure the overlayWidget has resized before using it to set the height
domNode.style.width = `${editor.getLayoutInfo().contentWidth}px`;
// TODO: set via onComputedHeight?
data.viewZoneHeight = domNode.offsetHeight;
const background = document.createElement('div');
// background.style.background = 'lightgreen';
data.descriptionZoneHeight = domNode.offsetHeight;
// We have to wait for the viewZone to finish rendering before adjusting the
// position of the overlayWidget (i.e. trigger it via onComputedHeight). If
// not the editor may report the wrong value for position of the lines.
const viewZone = {
afterLineNumber: getLineAfterViewZone() - 1,
afterLineNumber: getLineAfterDescriptionZone() - 1,
heightInPx: domNode.offsetHeight,
domNode: background,
domNode: document.createElement('div'),
onComputedHeight: () =>
data.overlayWidget && editor.layoutOverlayWidget(data.overlayWidget)
data.descriptionWidget &&
editor.layoutOverlayWidget(data.descriptionWidget)
};
data.viewZoneId = changeAccessor.addZone(viewZone);
data.descriptionZoneId = changeAccessor.addZone(viewZone);
};
// TODO: this is basically the same as viewZoneCallback, so DRY them out.
const outputZoneCallback = (
changeAccessor: editor.IViewZoneChangeAccessor
) => {
const editor = data.editor;
if (!editor) return;
// TODO: is there any point creating this here? I know it's cached, but
// would it not be better just sourced from the overlayWidget?
const outputNode = createOutputNode(editor);
// make sure the overlayWidget has resized before using it to set the height
outputNode.style.width = `${editor.getLayoutInfo().contentWidth}px`;
// TODO: set via onComputedHeight?
data.outputZoneHeight = outputNode.offsetHeight;
const background = document.createElement('div');
// background.style.background = 'lightpink';
// We have to wait for the viewZone to finish rendering before adjusting the
// position of the overlayWidget (i.e. trigger it via onComputedHeight). If
// not the editor may report the wrong value for position of the lines.
const viewZone = {
afterLineNumber: getLineAfterEditableRegion() - 1,
heightInPx: outputNode.offsetHeight,
domNode: background,
domNode: document.createElement('div'),
onComputedHeight: () =>
data.outputWidget && editor.layoutOverlayWidget(data.outputWidget)
};
@ -505,7 +493,6 @@ const Editor = (props: EditorProps): JSX.Element => {
const { description, title } = props;
const jawHeading = document.createElement('h3');
jawHeading.innerText = title;
// TODO: var was used here. Should it?
const domNode = document.createElement('div');
const desc = document.createElement('div');
const descContainer = document.createElement('div');
@ -515,8 +502,6 @@ const Editor = (props: EditorProps): JSX.Element => {
descContainer.appendChild(jawHeading);
descContainer.appendChild(desc);
desc.innerHTML = description;
// desc.style.background = 'white';
// domNode.style.background = 'lightgreen';
// TODO: the solution is probably just to use an overlay that's forced to
// follow the decorations.
// TODO: this is enough for Firefox, but Chrome needs more before the
@ -526,12 +511,10 @@ const Editor = (props: EditorProps): JSX.Element => {
domNode.style.zIndex = '10';
domNode.setAttribute('aria-hidden', 'true');
// domNode.style.background = 'lightYellow';
domNode.style.left = `${editor.getLayoutInfo().contentLeft}px`;
domNode.style.width = `${editor.getLayoutInfo().contentWidth}px`;
domNode.style.top = getViewZoneTop();
domNode.style.top = getDescriptionZoneTop();
data.descriptionNode = domNode;
return domNode;
}
@ -672,14 +655,14 @@ const Editor = (props: EditorProps): JSX.Element => {
}
// NOTE: this is where the view zone *should* be, not necessarily were it
// currently is. (see getLineAfterViewZone)
// currently is. (see getLineAfterDescriptionZone)
// TODO: DRY this and getOutputZoneTop out.
function getViewZoneTop() {
function getDescriptionZoneTop() {
const editor = data.editor;
const heightDelta = data.viewZoneHeight;
const heightDelta = data.descriptionZoneHeight;
if (editor) {
const top = `${
editor.getTopForLineNumber(getLineAfterViewZone()) -
editor.getTopForLineNumber(getLineAfterDescriptionZone()) -
heightDelta -
editor.getScrollTop()
}px`;
@ -705,9 +688,7 @@ const Editor = (props: EditorProps): JSX.Element => {
// It's not possible to directly access the current view zone so we track
// the region it should cover instead.
// TODO: DRY
function getLineAfterViewZone() {
// TODO: abstract away the data, ids etc.
function getLineAfterDescriptionZone() {
const range = data.model?.getDecorationRange(data.startEditDecId);
// if the first decoration is missing, this implies the region reaches the
// start of the editor.
@ -731,7 +712,6 @@ const Editor = (props: EditorProps): JSX.Element => {
return monacoRef.current?.Range.lift(iRange);
};
// TODO: TESTS!
// Make 100% sure this is inclusive.
const getLinesBetweenRanges = (
firstRange: RangeType,
@ -785,7 +765,6 @@ const Editor = (props: EditorProps): JSX.Element => {
}
};
// TODO: do this once after _monaco has been created.
const getStartOfEditor = () =>
monacoRef.current?.Range.lift({
startLineNumber: 1,
@ -869,7 +848,6 @@ const Editor = (props: EditorProps): JSX.Element => {
return newLines.map(({ range }) => range);
}
// TODO refactor this mess
// TODO this listener needs to be replaced on reset.
model.onDidChangeContent(e => {
// TODO: it would be nice if undoing could remove the warning, but
@ -893,7 +871,7 @@ const Editor = (props: EditorProps): JSX.Element => {
if (e.isUndoing) {
// TODO: can we be more targeted? Only update when they could get out of
// sync
updateViewZone();
updateDescriptionZone();
updateOutputZone();
return;
}
@ -922,7 +900,7 @@ const Editor = (props: EditorProps): JSX.Element => {
// have changed if a line has been added or removed
const handleDescriptionZoneChange = () => {
if (newLineRanges.length > 0 || deletedLine > 0) {
updateViewZone();
updateDescriptionZone();
}
};
@ -1117,7 +1095,7 @@ const Editor = (props: EditorProps): JSX.Element => {
const editor = data.editor;
editor?.layout();
if (data.startEditDecId) {
updateViewZone();
updateDescriptionZone();
updateOutputZone();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -1132,11 +1110,11 @@ const Editor = (props: EditorProps): JSX.Element => {
});
}
function updateViewZone() {
function updateDescriptionZone() {
const editor = data.editor;
editor?.changeViewZones(changeAccessor => {
changeAccessor.removeZone(data.viewZoneId);
viewZoneCallback(changeAccessor);
changeAccessor.removeZone(data.descriptionZoneId);
descriptionZoneCallback(changeAccessor);
});
}