aframe
Version:
A web framework for building virtual reality experiences.
200 lines (168 loc) • 6.39 kB
JavaScript
/* global DeviceOrientationEvent */
import { registerComponent } from '../../core/component.js';
import { AFRAME_INJECTED } from '../../constants/index.js';
var MODAL_CLASS = 'a-modal';
var DIALOG_CLASS = 'a-dialog';
var DIALOG_TEXT_CLASS = 'a-dialog-text';
var DIALOG_TEXT_CONTAINER_CLASS = 'a-dialog-text-container';
var DIALOG_BUTTONS_CONTAINER_CLASS = 'a-dialog-buttons-container';
var DIALOG_BUTTON_CLASS = 'a-dialog-button';
var DIALOG_ALLOW_BUTTON_CLASS = 'a-dialog-allow-button';
var DIALOG_DENY_BUTTON_CLASS = 'a-dialog-deny-button';
var DIALOG_OK_BUTTON_CLASS = 'a-dialog-ok-button';
/**
* UI for enabling device motion permission
*/
export var Component = registerComponent('device-orientation-permission-ui', {
schema: {
enabled: {default: true},
deviceMotionMessage: {
default: 'This immersive website requires access to your device motion sensors.'
},
httpsMessage: {
default: 'Access this site over HTTPS to enter VR mode and grant access to the device sensors.'
},
denyButtonText: {default: 'Deny'},
allowButtonText: {default: 'Allow'},
cancelButtonText: {default: 'Cancel'}
},
sceneOnly: true,
init: function () {
var self = this;
if (!this.data.enabled) { return; }
if (!window.isSecureContext) {
this.showHTTPAlert();
}
// Browser doesn't support or doesn't require permission to DeviceOrientationEvent API.
if (typeof DeviceOrientationEvent === 'undefined' || !DeviceOrientationEvent.requestPermission) {
this.permissionGranted = true;
return;
}
this.onDeviceMotionDialogAllowClicked = this.onDeviceMotionDialogAllowClicked.bind(this);
this.onDeviceMotionDialogDenyClicked = this.onDeviceMotionDialogDenyClicked.bind(this);
// Show dialog only if permission has not yet been granted.
DeviceOrientationEvent.requestPermission().then(function () {
self.el.emit('deviceorientationpermissiongranted');
self.permissionGranted = true;
}).catch(function () {
self.devicePermissionDialogEl = createPermissionDialog(
self.data.denyButtonText,
self.data.allowButtonText,
self.data.deviceMotionMessage,
self.onDeviceMotionDialogAllowClicked,
self.onDeviceMotionDialogDenyClicked);
self.el.appendChild(self.devicePermissionDialogEl);
});
},
remove: function () {
// This removes the modal screen
if (this.devicePermissionDialogEl) { this.el.removeChild(this.devicePermissionDialogEl); }
},
onDeviceMotionDialogDenyClicked: function () {
this.remove();
},
showHTTPAlert: function () {
var self = this;
var httpAlertEl = createAlertDialog(
self.data.cancelButtonText,
self.data.httpsMessage,
function () { self.el.removeChild(httpAlertEl); });
this.el.appendChild(httpAlertEl);
},
/**
* Enable device motion permission when clicked.
*/
onDeviceMotionDialogAllowClicked: function () {
var self = this;
this.el.emit('deviceorientationpermissionrequested');
DeviceOrientationEvent.requestPermission().then(function (response) {
if (response === 'granted') {
self.el.emit('deviceorientationpermissiongranted');
self.permissionGranted = true;
} else {
self.el.emit('deviceorientationpermissionrejected');
}
self.remove();
}).catch(console.error);
}
});
/**
* Create a modal dialog that request users permission to access the Device Motion API.
*
* @param {string} denyText
* @param {string} allowText
* @param {string} dialogText
* @param {function} onAllowClicked - click event handler
* @param {function} onDenyClicked - click event handler
*
* @returns {Element} Wrapper <div>.
*/
function createPermissionDialog (
denyText, allowText, dialogText, onAllowClicked, onDenyClicked) {
var buttonsContainer;
var denyButton;
var acceptButton;
buttonsContainer = document.createElement('div');
buttonsContainer.classList.add(DIALOG_BUTTONS_CONTAINER_CLASS);
// Buttons
denyButton = document.createElement('button');
denyButton.classList.add(DIALOG_BUTTON_CLASS, DIALOG_DENY_BUTTON_CLASS);
denyButton.setAttribute(AFRAME_INJECTED, '');
denyButton.innerHTML = denyText;
buttonsContainer.appendChild(denyButton);
acceptButton = document.createElement('button');
acceptButton.classList.add(DIALOG_BUTTON_CLASS, DIALOG_ALLOW_BUTTON_CLASS);
acceptButton.setAttribute(AFRAME_INJECTED, '');
acceptButton.innerHTML = allowText;
buttonsContainer.appendChild(acceptButton);
// Ask for sensor events to be used
acceptButton.addEventListener('click', function (evt) {
evt.stopPropagation();
onAllowClicked();
});
denyButton.addEventListener('click', function (evt) {
evt.stopPropagation();
onDenyClicked();
});
return createDialog(dialogText, buttonsContainer);
}
function createAlertDialog (closeText, dialogText, onOkClicked) {
var buttonsContainer;
var okButton;
buttonsContainer = document.createElement('div');
buttonsContainer.classList.add(DIALOG_BUTTONS_CONTAINER_CLASS);
// Buttons
okButton = document.createElement('button');
okButton.classList.add(DIALOG_BUTTON_CLASS, DIALOG_OK_BUTTON_CLASS);
okButton.setAttribute(AFRAME_INJECTED, '');
okButton.innerHTML = closeText;
buttonsContainer.appendChild(okButton);
// Ask for sensor events to be used
okButton.addEventListener('click', function (evt) {
evt.stopPropagation();
onOkClicked();
});
return createDialog(dialogText, buttonsContainer);
}
function createDialog (text, buttonsContainerEl) {
var modalContainer;
var dialog;
var dialogTextContainer;
var dialogText;
modalContainer = document.createElement('div');
modalContainer.classList.add(MODAL_CLASS);
modalContainer.setAttribute(AFRAME_INJECTED, '');
dialog = document.createElement('div');
dialog.className = DIALOG_CLASS;
dialog.setAttribute(AFRAME_INJECTED, '');
modalContainer.appendChild(dialog);
dialogTextContainer = document.createElement('div');
dialogTextContainer.classList.add(DIALOG_TEXT_CONTAINER_CLASS);
dialog.appendChild(dialogTextContainer);
dialogText = document.createElement('div');
dialogText.classList.add(DIALOG_TEXT_CLASS);
dialogText.innerHTML = text;
dialogTextContainer.appendChild(dialogText);
dialog.appendChild(buttonsContainerEl);
return modalContainer;
}