forked from EXT/VR180-Web-Player
109 lines
3.1 KiB
TypeScript
109 lines
3.1 KiB
TypeScript
import {
|
|
DEFAULT_PROJECTION,
|
|
PLAYER_SELECTOR,
|
|
type ProjectionMode,
|
|
VALID_PROJECTIONS
|
|
} from './config.js';
|
|
import { create2DControlPanel, createPlayButton, injectPlayerStyles } from './dom/dom.js';
|
|
import { createMediaAdapter, type SupportedMediaAdapter } from './media/media-adapter.js';
|
|
|
|
export type BootstrapContext = {
|
|
mediaAdapter: SupportedMediaAdapter;
|
|
playButton: HTMLButtonElement;
|
|
playerContainer: HTMLElement;
|
|
projectionMode: ProjectionMode;
|
|
};
|
|
|
|
export function bootstrapPlayer(playerBase: string, onReady: (context: BootstrapContext) => void): void {
|
|
injectPlayerStyles(playerBase);
|
|
|
|
onDocumentReady(() => {
|
|
const containers = document.querySelectorAll<HTMLElement>(PLAYER_SELECTOR);
|
|
|
|
if (containers.length === 0) {
|
|
console.error(`VR_WEB_PLAYER_DOM: Expected exactly one ${PLAYER_SELECTOR} container, found none.`);
|
|
return;
|
|
}
|
|
|
|
if (containers.length > 1) {
|
|
console.warn(`VR_WEB_PLAYER_DOM: This version supports exactly one ${PLAYER_SELECTOR} container per page. Found ${containers.length}; no player was initialized.`);
|
|
return;
|
|
}
|
|
|
|
const playerContainer = containers[0];
|
|
playerContainer.classList.add('vrwp');
|
|
|
|
const configuredProjection = (playerContainer.dataset.projection || DEFAULT_PROJECTION).trim().toLowerCase();
|
|
if (!VALID_PROJECTIONS.has(configuredProjection as ProjectionMode)) {
|
|
console.error(`VR_WEB_PLAYER_CONFIG: Unsupported data-projection="${configuredProjection}". Use "vr180" or "plane".`);
|
|
return;
|
|
}
|
|
|
|
const mediaAdapter = createMediaAdapter(playerContainer);
|
|
if (!mediaAdapter) {
|
|
console.error(`VR_WEB_PLAYER_DOM: ${PLAYER_SELECTOR} must contain exactly one supported media element: video or img.`);
|
|
return;
|
|
}
|
|
|
|
const playButton = createPlayButton();
|
|
playerContainer.appendChild(playButton);
|
|
playerContainer.appendChild(create2DControlPanel());
|
|
playButton.disabled = true;
|
|
mediaAdapter.bindLoadState({
|
|
onError: (event) => {
|
|
console.error(`VR_WEB_PLAYER_MEDIA: Failed to load ${mediaAdapter.kind} media.`, event);
|
|
playButton.disabled = true;
|
|
},
|
|
onReady: () => {
|
|
playButton.disabled = false;
|
|
}
|
|
});
|
|
mediaAdapter.load();
|
|
|
|
completeXrSupportCheck(playButton, () => {
|
|
onReady({
|
|
mediaAdapter,
|
|
playButton,
|
|
playerContainer,
|
|
projectionMode: configuredProjection as ProjectionMode
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
function onDocumentReady(callback: () => void): void {
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', callback, { once: true });
|
|
return;
|
|
}
|
|
|
|
callback();
|
|
}
|
|
|
|
function completeXrSupportCheck(playButton: HTMLButtonElement, onComplete: () => void): void {
|
|
if (!navigator.xr) {
|
|
markXrUnsupported(playButton);
|
|
onComplete();
|
|
return;
|
|
}
|
|
|
|
navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
|
|
if (supported) {
|
|
playButton.dataset.xrSupported = 'true';
|
|
} else {
|
|
markXrUnsupported(playButton);
|
|
}
|
|
|
|
onComplete();
|
|
}).catch((err) => {
|
|
console.error('XR Support Check Error:', err);
|
|
markXrUnsupported(playButton);
|
|
onComplete();
|
|
});
|
|
}
|
|
|
|
function markXrUnsupported(playButton: HTMLButtonElement): void {
|
|
playButton.dataset.xrSupported = 'false';
|
|
playButton.disabled = false;
|
|
}
|