@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
text/typescript
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.
*/
url?: string;
/**
* The mode in which the URL should be opened: NewTab, SameTab, NewWindow.
*/
mode: OpenURLMode = OpenURLMode.NewTab;
/**
* If true, the URL will be opened when the object with this component is clicked.
*/
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;
}
}
}