chore: extract recorder dialog into a class (#32233)
This commit is contained in:
parent
fc4d8f2bb6
commit
109cab66f1
|
|
@ -552,28 +552,14 @@ class TextAssertionTool implements RecorderTool {
|
||||||
private _recorder: Recorder;
|
private _recorder: Recorder;
|
||||||
private _hoverHighlight: HighlightModel | null = null;
|
private _hoverHighlight: HighlightModel | null = null;
|
||||||
private _action: actions.AssertAction | null = null;
|
private _action: actions.AssertAction | null = null;
|
||||||
private _dialogElement: HTMLElement | null = null;
|
private _dialog: Dialog;
|
||||||
private _acceptButton: HTMLElement;
|
|
||||||
private _cancelButton: HTMLElement;
|
|
||||||
private _keyboardListener: ((event: KeyboardEvent) => void) | undefined;
|
|
||||||
private _textCache = new Map<Element | ShadowRoot, ElementText>();
|
private _textCache = new Map<Element | ShadowRoot, ElementText>();
|
||||||
private _kind: 'text' | 'value';
|
private _kind: 'text' | 'value';
|
||||||
|
|
||||||
constructor(recorder: Recorder, kind: 'text' | 'value') {
|
constructor(recorder: Recorder, kind: 'text' | 'value') {
|
||||||
this._recorder = recorder;
|
this._recorder = recorder;
|
||||||
this._kind = kind;
|
this._kind = kind;
|
||||||
|
this._dialog = new Dialog(recorder);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor() {
|
cursor() {
|
||||||
|
|
@ -581,7 +567,7 @@ class TextAssertionTool implements RecorderTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
this._closeDialog();
|
this._dialog.close();
|
||||||
this._hoverHighlight = null;
|
this._hoverHighlight = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -590,7 +576,7 @@ class TextAssertionTool implements RecorderTool {
|
||||||
if (this._kind === 'value') {
|
if (this._kind === 'value') {
|
||||||
this._commitAssertValue();
|
this._commitAssertValue();
|
||||||
} else {
|
} else {
|
||||||
if (!this._dialogElement)
|
if (!this._dialog.isShowing())
|
||||||
this._showDialog();
|
this._showDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -611,7 +597,7 @@ class TextAssertionTool implements RecorderTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
onMouseMove(event: MouseEvent) {
|
onMouseMove(event: MouseEvent) {
|
||||||
if (this._dialogElement)
|
if (this._dialog.isShowing())
|
||||||
return;
|
return;
|
||||||
const target = this._recorder.deepEventTarget(event);
|
const target = this._recorder.deepEventTarget(event);
|
||||||
if (this._hoverHighlight?.elements[0] === target)
|
if (this._hoverHighlight?.elements[0] === target)
|
||||||
|
|
@ -691,9 +677,9 @@ class TextAssertionTool implements RecorderTool {
|
||||||
}
|
}
|
||||||
|
|
||||||
private _commit() {
|
private _commit() {
|
||||||
if (!this._action || !this._dialogElement)
|
if (!this._action || !this._dialog.isShowing())
|
||||||
return;
|
return;
|
||||||
this._closeDialog();
|
this._dialog.close();
|
||||||
this._recorder.delegate.recordAction?.(this._action);
|
this._recorder.delegate.recordAction?.(this._action);
|
||||||
this._recorder.delegate.setMode?.('recording');
|
this._recorder.delegate.setMode?.('recording');
|
||||||
}
|
}
|
||||||
|
|
@ -705,31 +691,6 @@ class TextAssertionTool implements RecorderTool {
|
||||||
if (!this._action || this._action.name !== 'assertText')
|
if (!this._action || this._action.name !== 'assertText')
|
||||||
return;
|
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 action = this._action;
|
||||||
const textElement = this._recorder.document.createElement('textarea');
|
const textElement = this._recorder.document.createElement('textarea');
|
||||||
textElement.setAttribute('spellcheck', 'false');
|
textElement.setAttribute('spellcheck', 'false');
|
||||||
|
|
@ -747,24 +708,18 @@ class TextAssertionTool implements RecorderTool {
|
||||||
textElement.classList.toggle('does-not-match', !matches);
|
textElement.classList.toggle('does-not-match', !matches);
|
||||||
};
|
};
|
||||||
textElement.addEventListener('input', updateAndValidate);
|
textElement.addEventListener('input', updateAndValidate);
|
||||||
bodyElement.appendChild(textElement);
|
|
||||||
|
|
||||||
this._dialogElement.appendChild(bodyElement);
|
const label = 'Assert that element contains text';
|
||||||
this._recorder.highlight.appendChild(this._dialogElement);
|
const dialogElement = this._dialog.show({
|
||||||
const position = this._recorder.highlight.tooltipPosition(this._recorder.highlight.firstBox()!, this._dialogElement);
|
label,
|
||||||
this._dialogElement.style.top = position.anchorTop + 'px';
|
body: textElement,
|
||||||
this._dialogElement.style.left = position.anchorLeft + 'px';
|
onCommit: () => this._commit(),
|
||||||
|
});
|
||||||
|
const position = this._recorder.highlight.tooltipPosition(this._recorder.highlight.firstBox()!, dialogElement);
|
||||||
|
this._dialog.moveTo(position.anchorTop, position.anchorLeft);
|
||||||
textElement.focus();
|
textElement.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _closeDialog() {
|
|
||||||
if (!this._dialogElement)
|
|
||||||
return;
|
|
||||||
this._dialogElement.remove();
|
|
||||||
this._recorder.document.removeEventListener('keydown', this._keyboardListener!);
|
|
||||||
this._dialogElement = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _commitAssertValue() {
|
private _commitAssertValue() {
|
||||||
if (this._kind !== 'value')
|
if (this._kind !== 'value')
|
||||||
return;
|
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 {
|
function deepActiveElement(document: Document): Element | null {
|
||||||
let activeElement = document.activeElement;
|
let activeElement = document.activeElement;
|
||||||
while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
|
while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue