@plattar/plattar-ar-adapter
Version:
Plattar AR Adapter for interfacing with Google & Apple WebAR
290 lines (289 loc) • 11.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const plattar_api_1 = require("@plattar/plattar-api");
const configurator_controller_1 = require("./controllers/configurator-controller");
const vto_controller_1 = require("./controllers/vto-controller");
const product_controller_1 = require("./controllers/product-controller");
const util_1 = require("../util/util");
const webxr_controller_1 = require("./controllers/webxr-controller");
const gallery_controller_1 = require("./controllers/gallery-controller");
const launcher_controller_1 = require("./controllers/launcher-controller");
/**
* This tracks the current embed type
*/
var EmbedType;
(function (EmbedType) {
EmbedType[EmbedType["Configurator"] = 0] = "Configurator";
EmbedType[EmbedType["Legacy"] = 1] = "Legacy";
EmbedType[EmbedType["VTO"] = 2] = "VTO";
EmbedType[EmbedType["WebXR"] = 3] = "WebXR";
EmbedType[EmbedType["Gallery"] = 4] = "Gallery";
EmbedType[EmbedType["Launcher"] = 5] = "Launcher";
EmbedType[EmbedType["None"] = 6] = "None";
})(EmbedType || (EmbedType = {}));
/**
* Controls the state of the observer
*/
var ObserverState;
(function (ObserverState) {
ObserverState[ObserverState["Locked"] = 0] = "Locked";
ObserverState[ObserverState["Unlocked"] = 1] = "Unlocked";
})(ObserverState || (ObserverState = {}));
/**
* This is the primary <plattar-embed /> node that allows easy embedding
* of Plattar related content
*/
class PlattarEmbed extends HTMLElement {
constructor() {
super();
// this is the current embed type, viewer by default
this._currentType = EmbedType.None;
this._observerState = ObserverState.Unlocked;
this._controller = null;
this._currentSceneID = null;
this._currentServer = null;
this._observer = null;
}
get viewer() {
return this._controller ? this._controller.element : null;
}
/**
* Begin observing all changes to this DOM element
*/
connectedCallback() {
this.create();
}
/**
* creates a brand new instance of this embed
*/
create() {
if (!this._observer) {
this._observer = new MutationObserver((mutations) => {
if (this._observerState === ObserverState.Unlocked) {
mutations.forEach((mutation) => {
if (mutation.type === "attributes") {
const attributeName = mutation.attributeName ? mutation.attributeName : "none";
if (this._currentType !== EmbedType.Legacy) {
this._CreateEmbed(attributeName);
}
else {
this._OnAttributesUpdated(attributeName);
}
}
});
}
});
this._observer.observe(this, {
attributes: true
});
}
const productID = this.hasAttribute("product-id") && !this.hasAttribute("scene-id") ? this.getAttribute("product-id") : null;
if (productID) {
this._currentType = EmbedType.Legacy;
this._CreateLegacyEmbed();
return this._controller;
}
this._CreateEmbed("none");
return this._controller;
}
/**
* Locks the observer so attribute changes do not trigger anything
*/
lockObserver() {
this._observerState = ObserverState.Locked;
}
/**
* Unlocks the observer so attribute changes will start to re-trigger properly
*/
unlockObserver() {
this._observerState = ObserverState.Unlocked;
}
/**
* Destroys the active instance of this embed and resets internal state to default
*/
destroy() {
if (this._controller) {
this._controller.removeRenderer();
this._controller = null;
}
this._currentType = EmbedType.None;
}
/**
* this is only used for backwards-compatible legacy embed types typically
* embedding products with variations (without a scene-id)
*/
_CreateLegacyEmbed() {
// server cannot be changed once its set - defaults to production
const server = this.hasAttribute("server") ? this.getAttribute("server") : "production";
if (util_1.Util.isValidServerLocation(server)) {
plattar_api_1.Server.create(plattar_api_1.Server.match(server || "production"));
this._controller = new product_controller_1.ProductController(this);
const init = this.hasAttribute("init") ? this.getAttribute("init") : null;
switch (init) {
case "viewer":
this.startViewer();
break;
case "qrcode":
this.startQRCode();
break;
}
}
else {
console.warn("PlattarEmbed.CreateLegacy - cannot create as server attribute " + server + " is invalid, embed status remains unchanged");
}
}
/**
* creates the embed
* this can also be called when attributes/state changes so embeds can be re-loaded
*/
_CreateEmbed(attributeName) {
// check if controller needs to be destroyed due to server change
const serverAttribute = this.hasAttribute("server") ? this.getAttribute("server") : "production";
if (this._currentServer !== serverAttribute) {
this._currentServer = serverAttribute || "production";
// reset the controller if any
if (this._controller) {
this._controller.removeRenderer();
this._controller = null;
}
}
if (!util_1.Util.isValidServerLocation(this._currentServer)) {
console.warn("PlattarEmbed.Create - cannot create as server attribute " + this._currentServer + " is invalid, embed status remains unchanged");
return;
}
plattar_api_1.Server.create(plattar_api_1.Server.match(this._currentServer || "production"));
const embedType = this.hasAttribute("embed-type") ? this.getAttribute("embed-type") : "configurator";
const currentEmbed = this._currentType;
if (embedType) {
switch (embedType.toLowerCase()) {
case "vto":
this._currentType = EmbedType.VTO;
break;
case "webxr":
this._currentType = EmbedType.WebXR;
break;
case "gallery":
this._currentType = EmbedType.Gallery;
break;
case "launcher":
this._currentType = EmbedType.Launcher;
break;
case "viewer":
case "configurator":
default:
this._currentType = EmbedType.Configurator;
}
}
// check if the controller needs to be re-created
if ((currentEmbed !== this._currentType) && this._controller) {
this._controller.removeRenderer();
this._controller = null;
}
const sceneID = this.hasAttribute("scene-id") ? this.getAttribute("scene-id") : null;
// if the provided SceneID doesn't match, we need to remove the controller
if ((sceneID !== this._currentSceneID) && this._controller) {
this._controller.removeRenderer();
this._controller = null;
}
this._currentSceneID = sceneID;
// scene-id is the absolute minimum in order to initialise the embeds
if (!this._currentSceneID) {
return;
}
// if the controller was removed due to state-change, we need to re-initialise it
if (!this._controller) {
switch (this._currentType) {
case EmbedType.Configurator:
this._controller = new configurator_controller_1.ConfiguratorController(this);
break;
case EmbedType.WebXR:
this._controller = new webxr_controller_1.WebXRController(this);
break;
case EmbedType.Gallery:
this._controller = new gallery_controller_1.GalleryController(this);
break;
case EmbedType.Launcher:
this._controller = new launcher_controller_1.LauncherController(this);
break;
case EmbedType.VTO:
this._controller = new vto_controller_1.VTOController(this);
break;
}
if (this._controller) {
const init = this.hasAttribute("init") ? this.getAttribute("init") : null;
switch (init) {
case "viewer":
this.startViewer();
break;
case "qrcode":
this.startQRCode();
break;
}
}
}
else {
this._OnAttributesUpdated(attributeName);
}
}
async initAR() {
if (!this._controller) {
throw new Error("PlattarEmbed.initAR() - cannot execute as controller has not loaded yet");
}
return this._controller.initAR();
}
async startAR() {
if (!this._controller) {
throw new Error("PlattarEmbed.startAR() - cannot execute as controller has not loaded yet");
}
return this._controller.startAR();
}
async startViewer() {
if (!this._controller) {
throw new Error("PlattarEmbed.startViewer() - cannot execute as controller has not loaded yet");
}
return this._controller.startRenderer();
}
async startQRCode(options = null) {
if (!this._controller) {
throw new Error("PlattarEmbed.startQRCode() - cannot execute as controller has not loaded yet");
}
return this._controller.startQRCode(options);
}
/**
* This will remove the currently active Renderer
*
* @returns - true if removed successfully, false otherwise
*/
removeRenderer() {
if (!this._controller) {
return false;
}
return this._controller.removeRenderer();
}
/**
* This is called by the observer if any of the embed attributes have changed
* based on the state of the embed, we update the internal structure accordingly
*/
_OnAttributesUpdated(attributeName) {
if (this._controller) {
this._controller.onAttributesUpdated(attributeName);
}
}
addEventListener(type, listener, options) {
// add to the element event listener
super.addEventListener(type, listener, options);
const eventType = 'arclick';
if (type === eventType) {
// automatically enable `show-ar-banner` to true if an arclick event is added
this.setAttribute('show-ar-banner', 'true');
// if this is a redirect url from an AR Action - we need to fire the event listener now
const url = new URL(location.href);
if (url.searchParams.get('plattar_ar_action') === 'true') {
setTimeout(() => {
this.dispatchEvent(new Event(eventType));
}, 200);
}
}
}
}
exports.default = PlattarEmbed;