chore: extract recorder dialog into a class (#32233)

This commit is contained in:
Pavel Feldman 2024-08-20 10:56:55 -07:00 committed by GitHub
parent fc4d8f2bb6
commit 109cab66f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -552,28 +552,14 @@ class TextAssertionTool implements RecorderTool {
private _recorder: Recorder;
private _hoverHighlight: HighlightModel | null = null;
private _action: actions.AssertAction | null = null;
private _dialogElement: HTMLElement | null = null;
private _acceptButton: HTMLElement;
private _cancelButton: HTMLElement;
private _keyboardListener: ((event: KeyboardEvent) => void) | undefined;
private _dialog: Dialog;
private _textCache = new Map<Element | ShadowRoot, ElementText>();
private _kind: 'text' | 'value';
constructor(recorder: Recorder, kind: 'text' | 'value') {
this._recorder = recorder;
this._kind = kind;
this._acceptButton = this._recorder.document.createElement('x-pw-tool-item');
this._acceptButton.title = 'Accept';
this._acceptButton.classList.add('accept');
this._acceptButton.appendChild(this._recorder.document.createElement('x-div'));
this._acceptButton.addEventListener('click', () => this._commit());
this._cancelButton = this._recorder.document.createElement('x-pw-tool-item');
this._cancelButton.title = 'Close';
this._cancelButton.classList.add('cancel');
this._cancelButton.appendChild(this._recorder.document.createElement('x-div'));
this._cancelButton.addEventListener('click', () => this._closeDialog());
this._dialog = new Dialog(recorder);
}
cursor() {
@ -581,7 +567,7 @@ class TextAssertionTool implements RecorderTool {
}
cleanup() {
this._closeDialog();
this._dialog.close();
this._hoverHighlight = null;
}
@ -590,7 +576,7 @@ class TextAssertionTool implements RecorderTool {
if (this._kind === 'value') {
this._commitAssertValue();
} else {
if (!this._dialogElement)
if (!this._dialog.isShowing())
this._showDialog();
}
}
@ -611,7 +597,7 @@ class TextAssertionTool implements RecorderTool {
}
onMouseMove(event: MouseEvent) {
if (this._dialogElement)
if (this._dialog.isShowing())
return;
const target = this._recorder.deepEventTarget(event);
if (this._hoverHighlight?.elements[0] === target)
@ -691,9 +677,9 @@ class TextAssertionTool implements RecorderTool {
}
private _commit() {
if (!this._action || !this._dialogElement)
if (!this._action || !this._dialog.isShowing())
return;
this._closeDialog();
this._dialog.close();
this._recorder.delegate.recordAction?.(this._action);
this._recorder.delegate.setMode?.('recording');
}
@ -705,31 +691,6 @@ class TextAssertionTool implements RecorderTool {
if (!this._action || this._action.name !== 'assertText')
return;
this._dialogElement = this._recorder.document.createElement('x-pw-dialog');
this._keyboardListener = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
this._closeDialog();
return;
}
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
if (this._dialogElement)
this._commit();
return;
}
};
this._recorder.document.addEventListener('keydown', this._keyboardListener, true);
const toolbarElement = this._recorder.document.createElement('x-pw-tools-list');
const labelElement = this._recorder.document.createElement('label');
labelElement.textContent = 'Assert that element contains text';
toolbarElement.appendChild(labelElement);
toolbarElement.appendChild(this._recorder.document.createElement('x-spacer'));
toolbarElement.appendChild(this._acceptButton);
toolbarElement.appendChild(this._cancelButton);
this._dialogElement.appendChild(toolbarElement);
const bodyElement = this._recorder.document.createElement('x-pw-dialog-body');
const action = this._action;
const textElement = this._recorder.document.createElement('textarea');
textElement.setAttribute('spellcheck', 'false');
@ -747,24 +708,18 @@ class TextAssertionTool implements RecorderTool {
textElement.classList.toggle('does-not-match', !matches);
};
textElement.addEventListener('input', updateAndValidate);
bodyElement.appendChild(textElement);
this._dialogElement.appendChild(bodyElement);
this._recorder.highlight.appendChild(this._dialogElement);
const position = this._recorder.highlight.tooltipPosition(this._recorder.highlight.firstBox()!, this._dialogElement);
this._dialogElement.style.top = position.anchorTop + 'px';
this._dialogElement.style.left = position.anchorLeft + 'px';
const label = 'Assert that element contains text';
const dialogElement = this._dialog.show({
label,
body: textElement,
onCommit: () => this._commit(),
});
const position = this._recorder.highlight.tooltipPosition(this._recorder.highlight.firstBox()!, dialogElement);
this._dialog.moveTo(position.anchorTop, position.anchorLeft);
textElement.focus();
}
private _closeDialog() {
if (!this._dialogElement)
return;
this._dialogElement.remove();
this._recorder.document.removeEventListener('keydown', this._keyboardListener!);
this._dialogElement = null;
}
private _commitAssertValue() {
if (this._kind !== 'value')
return;
@ -1219,6 +1174,87 @@ export class Recorder {
}
}
class Dialog {
private _recorder: Recorder;
private _dialogElement: HTMLElement | null = null;
private _keyboardListener: ((event: KeyboardEvent) => void) | undefined;
constructor(recorder: Recorder) {
this._recorder = recorder;
}
isShowing(): boolean {
return !!this._dialogElement;
}
show(options: {
label: string;
body: Element;
onCommit: () => void;
onCancel?: () => void;
}) {
const acceptButton = this._recorder.document.createElement('x-pw-tool-item');
acceptButton.title = 'Accept';
acceptButton.classList.add('accept');
acceptButton.appendChild(this._recorder.document.createElement('x-div'));
acceptButton.addEventListener('click', () => options.onCommit());
const cancelButton = this._recorder.document.createElement('x-pw-tool-item');
cancelButton.title = 'Close';
cancelButton.classList.add('cancel');
cancelButton.appendChild(this._recorder.document.createElement('x-div'));
cancelButton.addEventListener('click', () => {
this.close();
options.onCancel?.();
});
this._dialogElement = this._recorder.document.createElement('x-pw-dialog');
this._keyboardListener = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
this.close();
options.onCancel?.();
return;
}
if (event.key === 'Enter' && (event.ctrlKey || event.metaKey)) {
if (this._dialogElement)
options.onCommit();
return;
}
};
this._recorder.document.addEventListener('keydown', this._keyboardListener, true);
const toolbarElement = this._recorder.document.createElement('x-pw-tools-list');
const labelElement = this._recorder.document.createElement('label');
labelElement.textContent = options.label;
toolbarElement.appendChild(labelElement);
toolbarElement.appendChild(this._recorder.document.createElement('x-spacer'));
toolbarElement.appendChild(acceptButton);
toolbarElement.appendChild(cancelButton);
this._dialogElement.appendChild(toolbarElement);
const bodyElement = this._recorder.document.createElement('x-pw-dialog-body');
bodyElement.appendChild(options.body);
this._dialogElement.appendChild(bodyElement);
this._recorder.highlight.appendChild(this._dialogElement);
return this._dialogElement;
}
moveTo(top: number, left: number) {
if (!this._dialogElement)
return;
this._dialogElement.style.top = top + 'px';
this._dialogElement.style.left = left + 'px';
}
close() {
if (!this._dialogElement)
return;
this._dialogElement.remove();
this._recorder.document.removeEventListener('keydown', this._keyboardListener!);
this._dialogElement = null;
}
}
function deepActiveElement(document: Document): Element | null {
let activeElement = document.activeElement;
while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)