UNPKG

@needle-tools/engine

Version:

Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.

115 lines (103 loc) 3.51 kB
import { isDevEnvironment, showBalloonMessage } from "../../engine/debug/index.js"; import { serializable } from "../../engine/engine_serialization.js"; import { DeviceUtilities } from "../../engine/engine_utils.js"; import { Behaviour } from "../Component.js"; import { type IPointerClickHandler, PointerEventData } from "../ui/index.js"; import { ObjectRaycaster } from "../ui/Raycaster.js"; /** * OpenURLMode defines how a URL should be opened. */ export enum OpenURLMode { NewTab = 0, SameTab = 1, NewWindow = 2 } /** * OpenURL behaviour opens a URL in a new tab or window. * @category Interactivity * @group Components */ export class OpenURL extends Behaviour implements IPointerClickHandler { /** * The URL to open. */ @serializable() url?: string; /** * The mode in which the URL should be opened: NewTab, SameTab, NewWindow. */ @serializable() mode: OpenURLMode = OpenURLMode.NewTab; /** * If true, the URL will be opened when the object with this component is clicked. */ @serializable() clickable: boolean = true; /** * Opens the URL in a new tab or window. */ async open() { if (!this.url) { console.warn("OpenURL: URL is not set, can't open.", this); return; } this._validateUrl(); let url = this.url; if (!url.startsWith("mailto:") && url.includes("@")) { url = "mailto:" + url; } if (isDevEnvironment()) showBalloonMessage("Open URL: " + url) switch (this.mode) { case OpenURLMode.NewTab: if (DeviceUtilities.isSafari()) { globalThis.open(url, "_blank"); } else globalThis.open(url, "_blank"); break; case OpenURLMode.SameTab: // TODO: test if "same tab" now also works on iOS if (DeviceUtilities.isSafari() && DeviceUtilities.isiOS()) { globalThis.open(url, "_top"); } else globalThis.open(url, "_self"); break; case OpenURLMode.NewWindow: if (DeviceUtilities.isSafari()) { globalThis.open(url, "_top"); } else globalThis.open(url, "_new"); break; } } /** @internal */ start(): void { const raycaster = this.gameObject.getComponentInParent(ObjectRaycaster); if (!raycaster) this.gameObject.addComponent(ObjectRaycaster); } /** @internal */ onPointerEnter(args) { if (!args.used && this.clickable) this.context.input.setCursor("pointer"); } /** @internal */ onPointerExit() { if (this.clickable) this.context.input.unsetCursor("pointer"); } /** @internal */ onPointerClick(args: PointerEventData) { if (this.clickable && !args.used && this.url?.length) this.open(); } private _validateUrl() { if (!this.url) return; if (this.url.startsWith("www.")) { if (isDevEnvironment()) { console.warn("URL is not valid, adding https:// to the start of the URL", this.url); } this.url = "https://" + this.url; } } }