Next.js website for Rocky Mountain Vending company featuring: - Product catalog with Stripe integration - Service areas and parts pages - Admin dashboard with Clerk authentication - SEO optimized pages with JSON-LD structured data Co-authored-by: Cursor <cursoragent@cursor.com>
152 lines
4 KiB
Text
152 lines
4 KiB
Text
/**
|
|
* @license
|
|
* Copyright 2023 Google Inc.
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import type * as Bidi from 'webdriver-bidi-protocol';
|
|
|
|
import {
|
|
bindIsolatedHandle,
|
|
ElementHandle,
|
|
type AutofillData,
|
|
} from '../api/ElementHandle.js';
|
|
import {UnsupportedOperation} from '../common/Errors.js';
|
|
import type {AwaitableIterable} from '../common/types.js';
|
|
import {environment} from '../environment.js';
|
|
import {AsyncIterableUtil} from '../util/AsyncIterableUtil.js';
|
|
import {throwIfDisposed} from '../util/decorators.js';
|
|
|
|
import type {BidiFrame} from './Frame.js';
|
|
import {BidiJSHandle} from './JSHandle.js';
|
|
import type {BidiFrameRealm} from './Realm.js';
|
|
|
|
/**
|
|
* @internal
|
|
*/
|
|
export class BidiElementHandle<
|
|
ElementType extends Node = Element,
|
|
> extends ElementHandle<ElementType> {
|
|
#backendNodeId?: number;
|
|
|
|
static from<ElementType extends Node = Element>(
|
|
value: Bidi.Script.RemoteValue,
|
|
realm: BidiFrameRealm,
|
|
): BidiElementHandle<ElementType> {
|
|
return new BidiElementHandle(value, realm);
|
|
}
|
|
|
|
declare handle: BidiJSHandle<ElementType>;
|
|
|
|
constructor(value: Bidi.Script.RemoteValue, realm: BidiFrameRealm) {
|
|
super(BidiJSHandle.from(value, realm));
|
|
}
|
|
|
|
override get realm(): BidiFrameRealm {
|
|
// SAFETY: See the super call in the constructor.
|
|
return this.handle.realm as BidiFrameRealm;
|
|
}
|
|
|
|
override get frame(): BidiFrame {
|
|
return this.realm.environment;
|
|
}
|
|
|
|
remoteValue(): Bidi.Script.RemoteValue {
|
|
return this.handle.remoteValue();
|
|
}
|
|
|
|
@throwIfDisposed()
|
|
override async autofill(data: AutofillData): Promise<void> {
|
|
const client = this.frame.client;
|
|
const nodeInfo = await client.send('DOM.describeNode', {
|
|
objectId: this.handle.id,
|
|
});
|
|
const fieldId = nodeInfo.node.backendNodeId;
|
|
const frameId = this.frame._id;
|
|
await client.send('Autofill.trigger', {
|
|
fieldId,
|
|
frameId,
|
|
card: data.creditCard,
|
|
});
|
|
}
|
|
|
|
override async contentFrame(
|
|
this: BidiElementHandle<HTMLIFrameElement>,
|
|
): Promise<BidiFrame>;
|
|
@throwIfDisposed()
|
|
@bindIsolatedHandle
|
|
override async contentFrame(): Promise<BidiFrame | null> {
|
|
using handle = (await this.evaluateHandle(element => {
|
|
if (
|
|
element instanceof HTMLIFrameElement ||
|
|
element instanceof HTMLFrameElement
|
|
) {
|
|
return element.contentWindow;
|
|
}
|
|
return;
|
|
})) as BidiJSHandle;
|
|
const value = handle.remoteValue();
|
|
if (value.type === 'window') {
|
|
return (
|
|
this.frame
|
|
.page()
|
|
.frames()
|
|
.find(frame => {
|
|
return frame._id === value.value.context;
|
|
}) ?? null
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
override async uploadFile(
|
|
this: BidiElementHandle<HTMLInputElement>,
|
|
...files: string[]
|
|
): Promise<void> {
|
|
// Locate all files and confirm that they exist.
|
|
const path = environment.value.path;
|
|
if (path) {
|
|
files = files.map(file => {
|
|
if (path.win32.isAbsolute(file) || path.posix.isAbsolute(file)) {
|
|
return file;
|
|
} else {
|
|
return path.resolve(file);
|
|
}
|
|
});
|
|
}
|
|
await this.frame.setFiles(this, files);
|
|
}
|
|
|
|
override async *queryAXTree(
|
|
this: BidiElementHandle<HTMLElement>,
|
|
name?: string | undefined,
|
|
role?: string | undefined,
|
|
): AwaitableIterable<ElementHandle<Node>> {
|
|
const results = await this.frame.locateNodes(this, {
|
|
type: 'accessibility',
|
|
value: {
|
|
role,
|
|
name,
|
|
},
|
|
});
|
|
|
|
return yield* AsyncIterableUtil.map(results, node => {
|
|
// TODO: maybe change ownership since the default ownership is probably none.
|
|
return Promise.resolve(BidiElementHandle.from(node, this.realm));
|
|
});
|
|
}
|
|
|
|
override async backendNodeId(): Promise<number> {
|
|
if (!this.frame.page().browser().cdpSupported) {
|
|
throw new UnsupportedOperation();
|
|
}
|
|
if (this.#backendNodeId) {
|
|
return this.#backendNodeId;
|
|
}
|
|
const {node} = await this.frame.client.send('DOM.describeNode', {
|
|
objectId: this.handle.id,
|
|
});
|
|
this.#backendNodeId = node.backendNodeId;
|
|
return this.#backendNodeId;
|
|
}
|
|
}
|