Socket
Socket
Sign inDemoInstall

@pixi/accessibility

Package Overview
Dependencies
Maintainers
1
Versions
122
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@pixi/accessibility - npm Package Compare versions

Comparing version 5.2.4 to 5.3.0

995

dist/accessibility.js
/*!
* @pixi/accessibility - v5.2.4
* Compiled Sun, 03 May 2020 22:38:52 UTC
* @pixi/accessibility - v5.3.0
* Compiled Thu, 18 Jun 2020 23:27:40 UTC
*

@@ -9,4 +9,3 @@ * @pixi/accessibility is licensed under the MIT License.

this.PIXI = this.PIXI || {};
this.PIXI.accessibility = this.PIXI.accessibility || {};
var _pixi_accessibility = (function (exports, utils, display) {
var _pixi_accessibility = (function (exports, display, utils) {
'use strict';

@@ -16,7 +15,7 @@

* Default property values of accessible objects
* used by {@link PIXI.accessibility.AccessibilityManager}.
* used by {@link PIXI.AccessibilityManager}.
*
* @private
* @function accessibleTarget
* @memberof PIXI.accessibility
* @memberof PIXI
* @type {Object}

@@ -28,3 +27,3 @@ * @example

* MyObject.prototype,
* PIXI.accessibility.accessibleTarget
* PIXI.accessibleTarget
* );

@@ -41,3 +40,2 @@ */

accessible: false,
/**

@@ -51,3 +49,2 @@ * Sets the title attribute of the shadow div

accessibleTitle: null,
/**

@@ -60,3 +57,2 @@ * Sets the aria-label attribute of the shadow div

accessibleHint: null,
/**

@@ -69,3 +65,2 @@ * @member {number}

tabIndex: 0,
/**

@@ -77,3 +72,2 @@ * @member {boolean}

_accessibleActive: false,
/**

@@ -84,4 +78,3 @@ * @member {boolean}

*/
_accessibleDiv: false,
_accessibleDiv: null,
/**

@@ -96,3 +89,2 @@ * Specify the type of div the accessible layer is. Screen readers treat the element differently

accessibleType: 'button',
/**

@@ -107,3 +99,2 @@ * Specify the pointer-events the accessible div will use

accessiblePointerEvents: 'auto',
/**

@@ -118,2 +109,3 @@ * Setting to false will prevent any children inside this container to

accessibleChildren: true,
renderId: -1,
};

@@ -123,5 +115,3 @@

display.DisplayObject.mixin(accessibleTarget);
var KEY_CODE_TAB = 9;
var DIV_TOUCH_SIZE = 100;

@@ -131,3 +121,2 @@ var DIV_TOUCH_POS_X = 0;

var DIV_TOUCH_ZINDEX = 2;
var DIV_HOOK_SIZE = 1;

@@ -137,3 +126,2 @@ var DIV_HOOK_POS_X = -1000;

var DIV_HOOK_ZINDEX = 2;
/**

@@ -149,591 +137,468 @@ * The Accessibility manager recreates the ability to tab and have content read by screen readers.

* @class
* @memberof PIXI.accessibility
* @memberof PIXI
*/
var AccessibilityManager = function AccessibilityManager(renderer)
{
var AccessibilityManager = /** @class */ (function () {
/**
* @type {?HTMLElement}
* @private
* @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer
*/
this._hookDiv = null;
if (utils.isMobile.tablet || utils.isMobile.phone)
{
this.createTouchHook();
function AccessibilityManager(renderer) {
/**
* @type {?HTMLElement}
* @private
*/
this._hookDiv = null;
if (utils.isMobile.tablet || utils.isMobile.phone) {
this.createTouchHook();
}
// first we create a div that will sit over the PixiJS element. This is where the div overlays will go.
var div = document.createElement('div');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.position = 'absolute';
div.style.top = DIV_TOUCH_POS_X + "px";
div.style.left = DIV_TOUCH_POS_Y + "px";
div.style.zIndex = DIV_TOUCH_ZINDEX.toString();
/**
* This is the dom element that will sit over the PixiJS element. This is where the div overlays will go.
*
* @type {HTMLElement}
* @private
*/
this.div = div;
/**
* A simple pool for storing divs.
*
* @type {*}
* @private
*/
this.pool = [];
/**
* This is a tick used to check if an object is no longer being rendered.
*
* @type {Number}
* @private
*/
this.renderId = 0;
/**
* Setting this to true will visually show the divs.
*
* @type {boolean}
*/
this.debug = false;
/**
* The renderer this accessibility manager works for.
*
* @member {PIXI.AbstractRenderer}
*/
this.renderer = renderer;
/**
* The array of currently active accessible items.
*
* @member {Array<*>}
* @private
*/
this.children = [];
/**
* pre-bind the functions
*
* @type {Function}
* @private
*/
this._onKeyDown = this._onKeyDown.bind(this);
/**
* pre-bind the functions
*
* @type {Function}
* @private
*/
this._onMouseMove = this._onMouseMove.bind(this);
this._isActive = false;
this._isMobileAccessibility = false;
/**
* count to throttle div updates on android devices
* @type number
* @private
*/
this.androidUpdateCount = 0;
/**
* the frequency to update the div elements ()
* @private
*/
this.androidUpdateFrequency = 500; // 2fps
// let listen for tab.. once pressed we can fire up and show the accessibility layer
window.addEventListener('keydown', this._onKeyDown, false);
}
// first we create a div that will sit over the PixiJS element. This is where the div overlays will go.
var div = document.createElement('div');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.position = 'absolute';
div.style.top = DIV_TOUCH_POS_X + "px";
div.style.left = DIV_TOUCH_POS_Y + "px";
div.style.zIndex = DIV_TOUCH_ZINDEX;
Object.defineProperty(AccessibilityManager.prototype, "isActive", {
/**
* A flag
* @member {boolean}
* @readonly
*/
get: function () {
return this._isActive;
},
enumerable: false,
configurable: true
});
Object.defineProperty(AccessibilityManager.prototype, "isMobileAccessibility", {
/**
* A flag
* @member {boolean}
* @readonly
*/
get: function () {
return this._isMobileAccessibility;
},
enumerable: false,
configurable: true
});
/**
* This is the dom element that will sit over the PixiJS element. This is where the div overlays will go.
* Creates the touch hooks.
*
* @type {HTMLElement}
* @private
*/
this.div = div;
AccessibilityManager.prototype.createTouchHook = function () {
var _this = this;
var hookDiv = document.createElement('button');
hookDiv.style.width = DIV_HOOK_SIZE + "px";
hookDiv.style.height = DIV_HOOK_SIZE + "px";
hookDiv.style.position = 'absolute';
hookDiv.style.top = DIV_HOOK_POS_X + "px";
hookDiv.style.left = DIV_HOOK_POS_Y + "px";
hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString();
hookDiv.style.backgroundColor = '#FF0000';
hookDiv.title = 'select to enable accessability for this content';
hookDiv.addEventListener('focus', function () {
_this._isMobileAccessibility = true;
_this.activate();
_this.destroyTouchHook();
});
document.body.appendChild(hookDiv);
this._hookDiv = hookDiv;
};
/**
* A simple pool for storing divs.
* Destroys the touch hooks.
*
* @type {*}
* @private
*/
this.pool = [];
AccessibilityManager.prototype.destroyTouchHook = function () {
if (!this._hookDiv) {
return;
}
document.body.removeChild(this._hookDiv);
this._hookDiv = null;
};
/**
* This is a tick used to check if an object is no longer being rendered.
* Activating will cause the Accessibility layer to be shown.
* This is called when a user presses the tab key.
*
* @type {Number}
* @private
*/
this.renderId = 0;
AccessibilityManager.prototype.activate = function () {
if (this._isActive) {
return;
}
this._isActive = true;
window.document.addEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown, false);
// TODO: Remove casting when CanvasRenderer is converted
this.renderer.on('postrender', this.update, this);
if (this.renderer.view.parentNode) {
this.renderer.view.parentNode.appendChild(this.div);
}
};
/**
* Setting this to true will visually show the divs.
* Deactivating will cause the Accessibility layer to be hidden.
* This is called when a user moves the mouse.
*
* @type {boolean}
* @private
*/
this.debug = false;
AccessibilityManager.prototype.deactivate = function () {
if (!this._isActive || this._isMobileAccessibility) {
return;
}
this._isActive = false;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.addEventListener('keydown', this._onKeyDown, false);
// TODO: Remove casting when CanvasRenderer is converted
this.renderer.off('postrender', this.update);
if (this.div.parentNode) {
this.div.parentNode.removeChild(this.div);
}
};
/**
* The renderer this accessibility manager works for.
* This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
*
* @member {PIXI.AbstractRenderer}
* @private
* @param {PIXI.Container} displayObject - The DisplayObject to check.
*/
this.renderer = renderer;
AccessibilityManager.prototype.updateAccessibleObjects = function (displayObject) {
if (!displayObject.visible || !displayObject.accessibleChildren) {
return;
}
if (displayObject.accessible && displayObject.interactive) {
if (!displayObject._accessibleActive) {
this.addChild(displayObject);
}
displayObject.renderId = this.renderId;
}
var children = displayObject.children;
for (var i = 0; i < children.length; i++) {
this.updateAccessibleObjects(children[i]);
}
};
/**
* The array of currently active accessible items.
* Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
*
* @member {Array<*>}
* @private
*/
this.children = [];
AccessibilityManager.prototype.update = function () {
/* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,
* moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,
* so I am just running update every half a second, seems to fix it.
*/
var now = performance.now();
if (utils.isMobile.android.device && now < this.androidUpdateCount) {
return;
}
this.androidUpdateCount = now + this.androidUpdateFrequency;
if (!this.renderer.renderingToScreen) {
return;
}
// update children...
if (this.renderer._lastObjectRendered) {
this.updateAccessibleObjects(this.renderer._lastObjectRendered);
}
// TODO: Remove casting when CanvasRenderer is converted
var rect = this.renderer.view.getBoundingClientRect();
var resolution = this.renderer.resolution;
var sx = (rect.width / this.renderer.width) * resolution;
var sy = (rect.height / this.renderer.height) * resolution;
var div = this.div;
div.style.left = rect.left + "px";
div.style.top = rect.top + "px";
div.style.width = this.renderer.width + "px";
div.style.height = this.renderer.height + "px";
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
if (child.renderId !== this.renderId) {
child._accessibleActive = false;
utils.removeItems(this.children, i, 1);
this.div.removeChild(child._accessibleDiv);
this.pool.push(child._accessibleDiv);
child._accessibleDiv = null;
i--;
}
else {
// map div to display..
div = child._accessibleDiv;
var hitArea = child.hitArea;
var wt = child.worldTransform;
if (child.hitArea) {
div.style.left = (wt.tx + (hitArea.x * wt.a)) * sx + "px";
div.style.top = (wt.ty + (hitArea.y * wt.d)) * sy + "px";
div.style.width = hitArea.width * wt.a * sx + "px";
div.style.height = hitArea.height * wt.d * sy + "px";
}
else {
hitArea = child.getBounds();
this.capHitArea(hitArea);
div.style.left = hitArea.x * sx + "px";
div.style.top = hitArea.y * sy + "px";
div.style.width = hitArea.width * sx + "px";
div.style.height = hitArea.height * sy + "px";
// update button titles and hints if they exist and they've changed
if (div.title !== child.accessibleTitle && child.accessibleTitle !== null) {
div.title = child.accessibleTitle;
}
if (div.getAttribute('aria-label') !== child.accessibleHint
&& child.accessibleHint !== null) {
div.setAttribute('aria-label', child.accessibleHint);
}
}
// the title or index may have changed, if so lets update it!
if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex) {
div.title = child.accessibleTitle;
div.tabIndex = child.tabIndex;
if (this.debug)
{ this.updateDebugHTML(div); }
}
}
}
// increment the render id..
this.renderId++;
};
/**
* pre-bind the functions
* private function that will visually add the information to the
* accessability div
*
* @type {Function}
* @param {HTMLElement} div
*/
AccessibilityManager.prototype.updateDebugHTML = function (div) {
div.innerHTML = "type: " + div.type + "</br> title : " + div.title + "</br> tabIndex: " + div.tabIndex;
};
/**
* Adjust the hit area based on the bounds of a display object
*
* @param {PIXI.Rectangle} hitArea - Bounds of the child
*/
AccessibilityManager.prototype.capHitArea = function (hitArea) {
if (hitArea.x < 0) {
hitArea.width += hitArea.x;
hitArea.x = 0;
}
if (hitArea.y < 0) {
hitArea.height += hitArea.y;
hitArea.y = 0;
}
// TODO: Remove casting when CanvasRenderer is converted
if (hitArea.x + hitArea.width > this.renderer.width) {
hitArea.width = this.renderer.width - hitArea.x;
}
if (hitArea.y + hitArea.height > this.renderer.height) {
hitArea.height = this.renderer.height - hitArea.y;
}
};
/**
* Adds a DisplayObject to the accessibility manager
*
* @private
* @param {PIXI.DisplayObject} displayObject - The child to make accessible.
*/
this._onKeyDown = this._onKeyDown.bind(this);
AccessibilityManager.prototype.addChild = function (displayObject) {
// this.activate();
var div = this.pool.pop();
if (!div) {
div = document.createElement('button');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';
div.style.position = 'absolute';
div.style.zIndex = DIV_TOUCH_ZINDEX.toString();
div.style.borderStyle = 'none';
// ARIA attributes ensure that button title and hint updates are announced properly
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
// Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.
div.setAttribute('aria-live', 'off');
}
else {
div.setAttribute('aria-live', 'polite');
}
if (navigator.userAgent.match(/rv:.*Gecko\//)) {
// FireFox needs this to announce only the new button name
div.setAttribute('aria-relevant', 'additions');
}
else {
// required by IE, other browsers don't much care
div.setAttribute('aria-relevant', 'text');
}
div.addEventListener('click', this._onClick.bind(this));
div.addEventListener('focus', this._onFocus.bind(this));
div.addEventListener('focusout', this._onFocusOut.bind(this));
}
// set pointer events
div.style.pointerEvents = displayObject.accessiblePointerEvents;
// set the type, this defaults to button!
div.type = displayObject.accessibleType;
if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null) {
div.title = displayObject.accessibleTitle;
}
else if (!displayObject.accessibleHint
|| displayObject.accessibleHint === null) {
div.title = "displayObject " + displayObject.tabIndex;
}
if (displayObject.accessibleHint
&& displayObject.accessibleHint !== null) {
div.setAttribute('aria-label', displayObject.accessibleHint);
}
if (this.debug)
{ this.updateDebugHTML(div); }
displayObject._accessibleActive = true;
displayObject._accessibleDiv = div;
div.displayObject = displayObject;
this.children.push(displayObject);
this.div.appendChild(displayObject._accessibleDiv);
displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;
};
/**
* pre-bind the functions
* Maps the div button press to pixi's InteractionManager (click)
*
* @type {Function}
* @private
* @param {MouseEvent} e - The click event.
*/
this._onMouseMove = this._onMouseMove.bind(this);
AccessibilityManager.prototype._onClick = function (e) {
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'click', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'pointertap', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'tap', interactionManager.eventData);
};
/**
* A flag
* @type {boolean}
* @readonly
* Maps the div focus events to pixi's InteractionManager (mouseover)
*
* @private
* @param {FocusEvent} e - The focus event.
*/
this.isActive = false;
AccessibilityManager.prototype._onFocus = function (e) {
if (!e.target.getAttribute('aria-live')) {
e.target.setAttribute('aria-live', 'assertive');
}
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseover', interactionManager.eventData);
};
/**
* A flag
* @type {boolean}
* @readonly
* Maps the div focus events to pixi's InteractionManager (mouseout)
*
* @private
* @param {FocusEvent} e - The focusout event.
*/
this.isMobileAccessibility = false;
AccessibilityManager.prototype._onFocusOut = function (e) {
if (!e.target.getAttribute('aria-live')) {
e.target.setAttribute('aria-live', 'polite');
}
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseout', interactionManager.eventData);
};
/**
* count to throttle div updates on android devices
* @type number
* Is called when a key is pressed
*
* @private
* @param {KeyboardEvent} e - The keydown event.
*/
this.androidUpdateCount = 0;
AccessibilityManager.prototype._onKeyDown = function (e) {
if (e.keyCode !== KEY_CODE_TAB) {
return;
}
this.activate();
};
/**
* the frequency to update the div elements ()
* Is called when the mouse moves across the renderer element
*
* @private
* @param {MouseEvent} e - The mouse event.
*/
this.androidUpdateFrequency = 500; // 2fps
// let listen for tab.. once pressed we can fire up and show the accessibility layer
window.addEventListener('keydown', this._onKeyDown, false);
};
/**
* Creates the touch hooks.
*
* @private
*/
AccessibilityManager.prototype.createTouchHook = function createTouchHook ()
{
var this$1 = this;
var hookDiv = document.createElement('button');
hookDiv.style.width = DIV_HOOK_SIZE + "px";
hookDiv.style.height = DIV_HOOK_SIZE + "px";
hookDiv.style.position = 'absolute';
hookDiv.style.top = DIV_HOOK_POS_X + "px";
hookDiv.style.left = DIV_HOOK_POS_Y + "px";
hookDiv.style.zIndex = DIV_HOOK_ZINDEX;
hookDiv.style.backgroundColor = '#FF0000';
hookDiv.title = 'select to enable accessability for this content';
hookDiv.addEventListener('focus', function () {
this$1.isMobileAccessibility = true;
this$1.activate();
this$1.destroyTouchHook();
});
document.body.appendChild(hookDiv);
this._hookDiv = hookDiv;
};
/**
* Destroys the touch hooks.
*
* @private
*/
AccessibilityManager.prototype.destroyTouchHook = function destroyTouchHook ()
{
if (!this._hookDiv)
{
return;
}
document.body.removeChild(this._hookDiv);
this._hookDiv = null;
};
/**
* Activating will cause the Accessibility layer to be shown.
* This is called when a user presses the tab key.
*
* @private
*/
AccessibilityManager.prototype.activate = function activate ()
{
if (this.isActive)
{
return;
}
this.isActive = true;
window.document.addEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown, false);
this.renderer.on('postrender', this.update, this);
if (this.renderer.view.parentNode)
{
this.renderer.view.parentNode.appendChild(this.div);
}
};
/**
* Deactivating will cause the Accessibility layer to be hidden.
* This is called when a user moves the mouse.
*
* @private
*/
AccessibilityManager.prototype.deactivate = function deactivate ()
{
if (!this.isActive || this.isMobileAccessibility)
{
return;
}
this.isActive = false;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.addEventListener('keydown', this._onKeyDown, false);
this.renderer.off('postrender', this.update);
if (this.div.parentNode)
{
this.div.parentNode.removeChild(this.div);
}
};
/**
* This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
*
* @private
* @param {PIXI.Container} displayObject - The DisplayObject to check.
*/
AccessibilityManager.prototype.updateAccessibleObjects = function updateAccessibleObjects (displayObject)
{
if (!displayObject.visible || !displayObject.accessibleChildren)
{
return;
}
if (displayObject.accessible && displayObject.interactive)
{
if (!displayObject._accessibleActive)
{
this.addChild(displayObject);
AccessibilityManager.prototype._onMouseMove = function (e) {
if (e.movementX === 0 && e.movementY === 0) {
return;
}
this.deactivate();
};
/**
* Destroys the accessibility manager
*
*/
AccessibilityManager.prototype.destroy = function () {
this.destroyTouchHook();
this.div = null;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown);
this.pool = null;
this.children = null;
this.renderer = null;
};
return AccessibilityManager;
}());
displayObject.renderId = this.renderId;
}
var children = displayObject.children;
for (var i = 0; i < children.length; i++)
{
this.updateAccessibleObjects(children[i]);
}
};
/**
* Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
*
* @private
*/
AccessibilityManager.prototype.update = function update ()
{
/* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,
* moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,
* so I am just running update every half a second, seems to fix it.
*/
var now = performance.now();
if (utils.isMobile.android.device && now < this.androidUpdateCount)
{
return;
}
this.androidUpdateCount = now + this.androidUpdateFrequency;
if (!this.renderer.renderingToScreen)
{
return;
}
// update children...
this.updateAccessibleObjects(this.renderer._lastObjectRendered);
var rect = this.renderer.view.getBoundingClientRect();
var resolution = this.renderer.resolution;
var sx = (rect.width / this.renderer.width) * resolution;
var sy = (rect.height / this.renderer.height) * resolution;
var div = this.div;
div.style.left = (rect.left) + "px";
div.style.top = (rect.top) + "px";
div.style.width = (this.renderer.width) + "px";
div.style.height = (this.renderer.height) + "px";
for (var i = 0; i < this.children.length; i++)
{
var child = this.children[i];
if (child.renderId !== this.renderId)
{
child._accessibleActive = false;
utils.removeItems(this.children, i, 1);
this.div.removeChild(child._accessibleDiv);
this.pool.push(child._accessibleDiv);
child._accessibleDiv = null;
i--;
}
else
{
// map div to display..
div = child._accessibleDiv;
var hitArea = child.hitArea;
var wt = child.worldTransform;
if (child.hitArea)
{
div.style.left = ((wt.tx + (hitArea.x * wt.a)) * sx) + "px";
div.style.top = ((wt.ty + (hitArea.y * wt.d)) * sy) + "px";
div.style.width = (hitArea.width * wt.a * sx) + "px";
div.style.height = (hitArea.height * wt.d * sy) + "px";
}
else
{
hitArea = child.getBounds();
this.capHitArea(hitArea);
div.style.left = (hitArea.x * sx) + "px";
div.style.top = (hitArea.y * sy) + "px";
div.style.width = (hitArea.width * sx) + "px";
div.style.height = (hitArea.height * sy) + "px";
// update button titles and hints if they exist and they've changed
if (div.title !== child.accessibleTitle && child.accessibleTitle !== null)
{
div.title = child.accessibleTitle;
}
if (div.getAttribute('aria-label') !== child.accessibleHint
&& child.accessibleHint !== null)
{
div.setAttribute('aria-label', child.accessibleHint);
}
}
// the title or index may have changed, if so lets update it!
if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex)
{
div.title = child.accessibleTitle;
div.tabIndex = child.tabIndex;
if (this.debug) { this.updateDebugHTML(div); }
}
}
}
// increment the render id..
this.renderId++;
};
/**
* private function that will visually add the information to the
* accessability div
*
* @param {HTMLDivElement} div
*/
AccessibilityManager.prototype.updateDebugHTML = function updateDebugHTML (div)
{
div.innerHTML = "type: " + (div.type) + "</br> title : " + (div.title) + "</br> tabIndex: " + (div.tabIndex);
};
/**
* Adjust the hit area based on the bounds of a display object
*
* @param {PIXI.Rectangle} hitArea - Bounds of the child
*/
AccessibilityManager.prototype.capHitArea = function capHitArea (hitArea)
{
if (hitArea.x < 0)
{
hitArea.width += hitArea.x;
hitArea.x = 0;
}
if (hitArea.y < 0)
{
hitArea.height += hitArea.y;
hitArea.y = 0;
}
if (hitArea.x + hitArea.width > this.renderer.width)
{
hitArea.width = this.renderer.width - hitArea.x;
}
if (hitArea.y + hitArea.height > this.renderer.height)
{
hitArea.height = this.renderer.height - hitArea.y;
}
};
/**
* Adds a DisplayObject to the accessibility manager
*
* @private
* @param {PIXI.DisplayObject} displayObject - The child to make accessible.
*/
AccessibilityManager.prototype.addChild = function addChild (displayObject)
{
//this.activate();
var div = this.pool.pop();
if (!div)
{
div = document.createElement('button');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';
div.style.position = 'absolute';
div.style.zIndex = DIV_TOUCH_ZINDEX;
div.style.borderStyle = 'none';
// ARIA attributes ensure that button title and hint updates are announced properly
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1)
{
// Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.
div.setAttribute('aria-live', 'off');
}
else
{
div.setAttribute('aria-live', 'polite');
}
if (navigator.userAgent.match(/rv:.*Gecko\//))
{
// FireFox needs this to announce only the new button name
div.setAttribute('aria-relevant', 'additions');
}
else
{
// required by IE, other browsers don't much care
div.setAttribute('aria-relevant', 'text');
}
div.addEventListener('click', this._onClick.bind(this));
div.addEventListener('focus', this._onFocus.bind(this));
div.addEventListener('focusout', this._onFocusOut.bind(this));
}
// set pointer events
div.style.pointerEvents = displayObject.accessiblePointerEvents;
// set the type, this defaults to button!
div.type = displayObject.accessibleType;
if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null)
{
div.title = displayObject.accessibleTitle;
}
else if (!displayObject.accessibleHint
|| displayObject.accessibleHint === null)
{
div.title = "displayObject " + (displayObject.tabIndex);
}
if (displayObject.accessibleHint
&& displayObject.accessibleHint !== null)
{
div.setAttribute('aria-label', displayObject.accessibleHint);
}
if (this.debug) { this.updateDebugHTML(div); }
displayObject._accessibleActive = true;
displayObject._accessibleDiv = div;
div.displayObject = displayObject;
this.children.push(displayObject);
this.div.appendChild(displayObject._accessibleDiv);
displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;
};
/**
* Maps the div button press to pixi's InteractionManager (click)
*
* @private
* @param {MouseEvent} e - The click event.
*/
AccessibilityManager.prototype._onClick = function _onClick (e)
{
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'click', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'pointertap', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'tap', interactionManager.eventData);
};
/**
* Maps the div focus events to pixi's InteractionManager (mouseover)
*
* @private
* @param {FocusEvent} e - The focus event.
*/
AccessibilityManager.prototype._onFocus = function _onFocus (e)
{
if (!e.target.getAttribute('aria-live', 'off'))
{
e.target.setAttribute('aria-live', 'assertive');
}
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseover', interactionManager.eventData);
};
/**
* Maps the div focus events to pixi's InteractionManager (mouseout)
*
* @private
* @param {FocusEvent} e - The focusout event.
*/
AccessibilityManager.prototype._onFocusOut = function _onFocusOut (e)
{
if (!e.target.getAttribute('aria-live', 'off'))
{
e.target.setAttribute('aria-live', 'polite');
}
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseout', interactionManager.eventData);
};
/**
* Is called when a key is pressed
*
* @private
* @param {KeyboardEvent} e - The keydown event.
*/
AccessibilityManager.prototype._onKeyDown = function _onKeyDown (e)
{
if (e.keyCode !== KEY_CODE_TAB)
{
return;
}
this.activate();
};
/**
* Is called when the mouse moves across the renderer element
*
* @private
* @param {MouseEvent} e - The mouse event.
*/
AccessibilityManager.prototype._onMouseMove = function _onMouseMove (e)
{
if (e.movementX === 0 && e.movementY === 0)
{
return;
}
this.deactivate();
};
/**
* Destroys the accessibility manager
*
*/
AccessibilityManager.prototype.destroy = function destroy ()
{
this.destroyTouchHook();
this.div = null;
for (var i = 0; i < this.children.length; i++)
{
this.children[i].div = null;
}
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown);
this.pool = null;
this.children = null;
this.renderer = null;
};
/**
* This namespace contains an accessibility plugin for allowing interaction via the keyboard.
*
* Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
* See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.Renderer#plugins}.
* @namespace PIXI.accessibility
*/
exports.AccessibilityManager = AccessibilityManager;

@@ -744,4 +609,4 @@ exports.accessibleTarget = accessibleTarget;

}({}, PIXI.utils, PIXI));
Object.assign(this.PIXI.accessibility, _pixi_accessibility);
}({}, PIXI, PIXI.utils));
Object.assign(this.PIXI, _pixi_accessibility);
//# sourceMappingURL=accessibility.js.map
/*!
* @pixi/accessibility - v5.2.4
* Compiled Sun, 03 May 2020 22:38:52 UTC
* @pixi/accessibility - v5.3.0
* Compiled Thu, 18 Jun 2020 23:27:40 UTC
*

@@ -8,3 +8,3 @@ * @pixi/accessibility is licensed under the MIT License.

*/
this.PIXI=this.PIXI||{},this.PIXI.accessibility=this.PIXI.accessibility||{};var _pixi_accessibility=function(e,t,i){"use strict";var s={accessible:!1,accessibleTitle:null,accessibleHint:null,tabIndex:0,_accessibleActive:!1,_accessibleDiv:!1,accessibleType:"button",accessiblePointerEvents:"auto",accessibleChildren:!0};PIXI.DisplayObject.mixin(s);var n=function(e){this._hookDiv=null,(t.isMobile.tablet||t.isMobile.phone)&&this.createTouchHook();var i=document.createElement("div");i.style.width="100px",i.style.height="100px",i.style.position="absolute",i.style.top="0px",i.style.left="0px",i.style.zIndex=2,this.div=i,this.pool=[],this.renderId=0,this.debug=!1,this.renderer=e,this.children=[],this._onKeyDown=this._onKeyDown.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this.isActive=!1,this.isMobileAccessibility=!1,this.androidUpdateCount=0,this.androidUpdateFrequency=500,window.addEventListener("keydown",this._onKeyDown,!1)};return n.prototype.createTouchHook=function(){var e=this,t=document.createElement("button");t.style.width="1px",t.style.height="1px",t.style.position="absolute",t.style.top="-1000px",t.style.left="-1000px",t.style.zIndex=2,t.style.backgroundColor="#FF0000",t.title="select to enable accessability for this content",t.addEventListener("focus",function(){e.isMobileAccessibility=!0,e.activate(),e.destroyTouchHook()}),document.body.appendChild(t),this._hookDiv=t},n.prototype.destroyTouchHook=function(){this._hookDiv&&(document.body.removeChild(this._hookDiv),this._hookDiv=null)},n.prototype.activate=function(){this.isActive||(this.isActive=!0,window.document.addEventListener("mousemove",this._onMouseMove,!0),window.removeEventListener("keydown",this._onKeyDown,!1),this.renderer.on("postrender",this.update,this),this.renderer.view.parentNode&&this.renderer.view.parentNode.appendChild(this.div))},n.prototype.deactivate=function(){this.isActive&&!this.isMobileAccessibility&&(this.isActive=!1,window.document.removeEventListener("mousemove",this._onMouseMove,!0),window.addEventListener("keydown",this._onKeyDown,!1),this.renderer.off("postrender",this.update),this.div.parentNode&&this.div.parentNode.removeChild(this.div))},n.prototype.updateAccessibleObjects=function(e){if(e.visible&&e.accessibleChildren){e.accessible&&e.interactive&&(e._accessibleActive||this.addChild(e),e.renderId=this.renderId);for(var t=e.children,i=0;i<t.length;i++)this.updateAccessibleObjects(t[i])}},n.prototype.update=function(){var e=performance.now();if(!(t.isMobile.android.device&&e<this.androidUpdateCount)&&(this.androidUpdateCount=e+this.androidUpdateFrequency,this.renderer.renderingToScreen)){this.updateAccessibleObjects(this.renderer._lastObjectRendered);var i=this.renderer.view.getBoundingClientRect(),s=this.renderer.resolution,n=i.width/this.renderer.width*s,o=i.height/this.renderer.height*s,r=this.div;r.style.left=i.left+"px",r.style.top=i.top+"px",r.style.width=this.renderer.width+"px",r.style.height=this.renderer.height+"px";for(var a=0;a<this.children.length;a++){var l=this.children[a];if(l.renderId!==this.renderId)l._accessibleActive=!1,t.removeItems(this.children,a,1),this.div.removeChild(l._accessibleDiv),this.pool.push(l._accessibleDiv),l._accessibleDiv=null,a--;else{r=l._accessibleDiv;var c=l.hitArea,d=l.worldTransform;l.hitArea?(r.style.left=(d.tx+c.x*d.a)*n+"px",r.style.top=(d.ty+c.y*d.d)*o+"px",r.style.width=c.width*d.a*n+"px",r.style.height=c.height*d.d*o+"px"):(c=l.getBounds(),this.capHitArea(c),r.style.left=c.x*n+"px",r.style.top=c.y*o+"px",r.style.width=c.width*n+"px",r.style.height=c.height*o+"px",r.title!==l.accessibleTitle&&null!==l.accessibleTitle&&(r.title=l.accessibleTitle),r.getAttribute("aria-label")!==l.accessibleHint&&null!==l.accessibleHint&&r.setAttribute("aria-label",l.accessibleHint)),l.accessibleTitle===r.title&&l.tabIndex===r.tabIndex||(r.title=l.accessibleTitle,r.tabIndex=l.tabIndex,this.debug&&this.updateDebugHTML(r))}}this.renderId++}},n.prototype.updateDebugHTML=function(e){e.innerHTML="type: "+e.type+"</br> title : "+e.title+"</br> tabIndex: "+e.tabIndex},n.prototype.capHitArea=function(e){e.x<0&&(e.width+=e.x,e.x=0),e.y<0&&(e.height+=e.y,e.y=0),e.x+e.width>this.renderer.width&&(e.width=this.renderer.width-e.x),e.y+e.height>this.renderer.height&&(e.height=this.renderer.height-e.y)},n.prototype.addChild=function(e){var t=this.pool.pop();t||((t=document.createElement("button")).style.width="100px",t.style.height="100px",t.style.backgroundColor=this.debug?"rgba(255,255,255,0.5)":"transparent",t.style.position="absolute",t.style.zIndex=2,t.style.borderStyle="none",navigator.userAgent.toLowerCase().indexOf("chrome")>-1?t.setAttribute("aria-live","off"):t.setAttribute("aria-live","polite"),navigator.userAgent.match(/rv:.*Gecko\//)?t.setAttribute("aria-relevant","additions"):t.setAttribute("aria-relevant","text"),t.addEventListener("click",this._onClick.bind(this)),t.addEventListener("focus",this._onFocus.bind(this)),t.addEventListener("focusout",this._onFocusOut.bind(this))),t.style.pointerEvents=e.accessiblePointerEvents,t.type=e.accessibleType,e.accessibleTitle&&null!==e.accessibleTitle?t.title=e.accessibleTitle:e.accessibleHint&&null!==e.accessibleHint||(t.title="displayObject "+e.tabIndex),e.accessibleHint&&null!==e.accessibleHint&&t.setAttribute("aria-label",e.accessibleHint),this.debug&&this.updateDebugHTML(t),e._accessibleActive=!0,e._accessibleDiv=t,t.displayObject=e,this.children.push(e),this.div.appendChild(e._accessibleDiv),e._accessibleDiv.tabIndex=e.tabIndex},n.prototype._onClick=function(e){var t=this.renderer.plugins.interaction;t.dispatchEvent(e.target.displayObject,"click",t.eventData),t.dispatchEvent(e.target.displayObject,"pointertap",t.eventData),t.dispatchEvent(e.target.displayObject,"tap",t.eventData)},n.prototype._onFocus=function(e){e.target.getAttribute("aria-live","off")||e.target.setAttribute("aria-live","assertive");var t=this.renderer.plugins.interaction;t.dispatchEvent(e.target.displayObject,"mouseover",t.eventData)},n.prototype._onFocusOut=function(e){e.target.getAttribute("aria-live","off")||e.target.setAttribute("aria-live","polite");var t=this.renderer.plugins.interaction;t.dispatchEvent(e.target.displayObject,"mouseout",t.eventData)},n.prototype._onKeyDown=function(e){9===e.keyCode&&this.activate()},n.prototype._onMouseMove=function(e){0===e.movementX&&0===e.movementY||this.deactivate()},n.prototype.destroy=function(){this.destroyTouchHook(),this.div=null;for(var e=0;e<this.children.length;e++)this.children[e].div=null;window.document.removeEventListener("mousemove",this._onMouseMove,!0),window.removeEventListener("keydown",this._onKeyDown),this.pool=null,this.children=null,this.renderer=null},e.AccessibilityManager=n,e.accessibleTarget=s,e}({},PIXI.utils);Object.assign(this.PIXI.accessibility,_pixi_accessibility);
this.PIXI=this.PIXI||{};var _pixi_accessibility=function(e,t,i){"use strict";var s={accessible:!1,accessibleTitle:null,accessibleHint:null,tabIndex:0,_accessibleActive:!1,_accessibleDiv:null,accessibleType:"button",accessiblePointerEvents:"auto",accessibleChildren:!0,renderId:-1};t.DisplayObject.mixin(s);var n=100,o=0,r=0,a=2,l=function(){function e(e){this._hookDiv=null,(i.isMobile.tablet||i.isMobile.phone)&&this.createTouchHook();var t=document.createElement("div");t.style.width=n+"px",t.style.height=n+"px",t.style.position="absolute",t.style.top=o+"px",t.style.left=r+"px",t.style.zIndex=a.toString(),this.div=t,this.pool=[],this.renderId=0,this.debug=!1,this.renderer=e,this.children=[],this._onKeyDown=this._onKeyDown.bind(this),this._onMouseMove=this._onMouseMove.bind(this),this._isActive=!1,this._isMobileAccessibility=!1,this.androidUpdateCount=0,this.androidUpdateFrequency=500,window.addEventListener("keydown",this._onKeyDown,!1)}return Object.defineProperty(e.prototype,"isActive",{get:function(){return this._isActive},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"isMobileAccessibility",{get:function(){return this._isMobileAccessibility},enumerable:!1,configurable:!0}),e.prototype.createTouchHook=function(){var e=this,t=document.createElement("button");t.style.width="1px",t.style.height="1px",t.style.position="absolute",t.style.top="-1000px",t.style.left="-1000px",t.style.zIndex=2..toString(),t.style.backgroundColor="#FF0000",t.title="select to enable accessability for this content",t.addEventListener("focus",function(){e._isMobileAccessibility=!0,e.activate(),e.destroyTouchHook()}),document.body.appendChild(t),this._hookDiv=t},e.prototype.destroyTouchHook=function(){this._hookDiv&&(document.body.removeChild(this._hookDiv),this._hookDiv=null)},e.prototype.activate=function(){this._isActive||(this._isActive=!0,window.document.addEventListener("mousemove",this._onMouseMove,!0),window.removeEventListener("keydown",this._onKeyDown,!1),this.renderer.on("postrender",this.update,this),this.renderer.view.parentNode&&this.renderer.view.parentNode.appendChild(this.div))},e.prototype.deactivate=function(){this._isActive&&!this._isMobileAccessibility&&(this._isActive=!1,window.document.removeEventListener("mousemove",this._onMouseMove,!0),window.addEventListener("keydown",this._onKeyDown,!1),this.renderer.off("postrender",this.update),this.div.parentNode&&this.div.parentNode.removeChild(this.div))},e.prototype.updateAccessibleObjects=function(e){if(e.visible&&e.accessibleChildren){e.accessible&&e.interactive&&(e._accessibleActive||this.addChild(e),e.renderId=this.renderId);for(var t=e.children,i=0;i<t.length;i++)this.updateAccessibleObjects(t[i])}},e.prototype.update=function(){var e=performance.now();if(!(i.isMobile.android.device&&e<this.androidUpdateCount)&&(this.androidUpdateCount=e+this.androidUpdateFrequency,this.renderer.renderingToScreen)){this.renderer._lastObjectRendered&&this.updateAccessibleObjects(this.renderer._lastObjectRendered);var t=this.renderer.view.getBoundingClientRect(),s=this.renderer.resolution,n=t.width/this.renderer.width*s,o=t.height/this.renderer.height*s,r=this.div;r.style.left=t.left+"px",r.style.top=t.top+"px",r.style.width=this.renderer.width+"px",r.style.height=this.renderer.height+"px";for(var a=0;a<this.children.length;a++){var l=this.children[a];if(l.renderId!==this.renderId)l._accessibleActive=!1,i.removeItems(this.children,a,1),this.div.removeChild(l._accessibleDiv),this.pool.push(l._accessibleDiv),l._accessibleDiv=null,a--;else{r=l._accessibleDiv;var c=l.hitArea,d=l.worldTransform;l.hitArea?(r.style.left=(d.tx+c.x*d.a)*n+"px",r.style.top=(d.ty+c.y*d.d)*o+"px",r.style.width=c.width*d.a*n+"px",r.style.height=c.height*d.d*o+"px"):(c=l.getBounds(),this.capHitArea(c),r.style.left=c.x*n+"px",r.style.top=c.y*o+"px",r.style.width=c.width*n+"px",r.style.height=c.height*o+"px",r.title!==l.accessibleTitle&&null!==l.accessibleTitle&&(r.title=l.accessibleTitle),r.getAttribute("aria-label")!==l.accessibleHint&&null!==l.accessibleHint&&r.setAttribute("aria-label",l.accessibleHint)),l.accessibleTitle===r.title&&l.tabIndex===r.tabIndex||(r.title=l.accessibleTitle,r.tabIndex=l.tabIndex,this.debug&&this.updateDebugHTML(r))}}this.renderId++}},e.prototype.updateDebugHTML=function(e){e.innerHTML="type: "+e.type+"</br> title : "+e.title+"</br> tabIndex: "+e.tabIndex},e.prototype.capHitArea=function(e){e.x<0&&(e.width+=e.x,e.x=0),e.y<0&&(e.height+=e.y,e.y=0),e.x+e.width>this.renderer.width&&(e.width=this.renderer.width-e.x),e.y+e.height>this.renderer.height&&(e.height=this.renderer.height-e.y)},e.prototype.addChild=function(e){var t=this.pool.pop();t||((t=document.createElement("button")).style.width=n+"px",t.style.height=n+"px",t.style.backgroundColor=this.debug?"rgba(255,255,255,0.5)":"transparent",t.style.position="absolute",t.style.zIndex=a.toString(),t.style.borderStyle="none",navigator.userAgent.toLowerCase().indexOf("chrome")>-1?t.setAttribute("aria-live","off"):t.setAttribute("aria-live","polite"),navigator.userAgent.match(/rv:.*Gecko\//)?t.setAttribute("aria-relevant","additions"):t.setAttribute("aria-relevant","text"),t.addEventListener("click",this._onClick.bind(this)),t.addEventListener("focus",this._onFocus.bind(this)),t.addEventListener("focusout",this._onFocusOut.bind(this))),t.style.pointerEvents=e.accessiblePointerEvents,t.type=e.accessibleType,e.accessibleTitle&&null!==e.accessibleTitle?t.title=e.accessibleTitle:e.accessibleHint&&null!==e.accessibleHint||(t.title="displayObject "+e.tabIndex),e.accessibleHint&&null!==e.accessibleHint&&t.setAttribute("aria-label",e.accessibleHint),this.debug&&this.updateDebugHTML(t),e._accessibleActive=!0,e._accessibleDiv=t,t.displayObject=e,this.children.push(e),this.div.appendChild(e._accessibleDiv),e._accessibleDiv.tabIndex=e.tabIndex},e.prototype._onClick=function(e){var t=this.renderer.plugins.interaction;t.dispatchEvent(e.target.displayObject,"click",t.eventData),t.dispatchEvent(e.target.displayObject,"pointertap",t.eventData),t.dispatchEvent(e.target.displayObject,"tap",t.eventData)},e.prototype._onFocus=function(e){e.target.getAttribute("aria-live")||e.target.setAttribute("aria-live","assertive");var t=this.renderer.plugins.interaction;t.dispatchEvent(e.target.displayObject,"mouseover",t.eventData)},e.prototype._onFocusOut=function(e){e.target.getAttribute("aria-live")||e.target.setAttribute("aria-live","polite");var t=this.renderer.plugins.interaction;t.dispatchEvent(e.target.displayObject,"mouseout",t.eventData)},e.prototype._onKeyDown=function(e){9===e.keyCode&&this.activate()},e.prototype._onMouseMove=function(e){0===e.movementX&&0===e.movementY||this.deactivate()},e.prototype.destroy=function(){this.destroyTouchHook(),this.div=null,window.document.removeEventListener("mousemove",this._onMouseMove,!0),window.removeEventListener("keydown",this._onKeyDown),this.pool=null,this.children=null,this.renderer=null},e}();return e.AccessibilityManager=l,e.accessibleTarget=s,e}({},PIXI,PIXI.utils);Object.assign(this.PIXI,_pixi_accessibility);
//# sourceMappingURL=accessibility.min.js.map
/*!
* @pixi/accessibility - v5.2.4
* Compiled Sun, 03 May 2020 22:38:52 UTC
* @pixi/accessibility - v5.3.0
* Compiled Thu, 18 Jun 2020 23:27:40 UTC
*

@@ -8,12 +8,12 @@ * @pixi/accessibility is licensed under the MIT License.

*/
import { DisplayObject } from '@pixi/display';
import { isMobile, removeItems } from '@pixi/utils';
import { DisplayObject } from '@pixi/display';
/**
* Default property values of accessible objects
* used by {@link PIXI.accessibility.AccessibilityManager}.
* used by {@link PIXI.AccessibilityManager}.
*
* @private
* @function accessibleTarget
* @memberof PIXI.accessibility
* @memberof PIXI
* @type {Object}

@@ -25,3 +25,3 @@ * @example

* MyObject.prototype,
* PIXI.accessibility.accessibleTarget
* PIXI.accessibleTarget
* );

@@ -38,3 +38,2 @@ */

accessible: false,
/**

@@ -48,3 +47,2 @@ * Sets the title attribute of the shadow div

accessibleTitle: null,
/**

@@ -57,3 +55,2 @@ * Sets the aria-label attribute of the shadow div

accessibleHint: null,
/**

@@ -66,3 +63,2 @@ * @member {number}

tabIndex: 0,
/**

@@ -74,3 +70,2 @@ * @member {boolean}

_accessibleActive: false,
/**

@@ -81,4 +76,3 @@ * @member {boolean}

*/
_accessibleDiv: false,
_accessibleDiv: null,
/**

@@ -93,3 +87,2 @@ * Specify the type of div the accessible layer is. Screen readers treat the element differently

accessibleType: 'button',
/**

@@ -104,3 +97,2 @@ * Specify the pointer-events the accessible div will use

accessiblePointerEvents: 'auto',
/**

@@ -115,2 +107,3 @@ * Setting to false will prevent any children inside this container to

accessibleChildren: true,
renderId: -1,
};

@@ -120,5 +113,3 @@

DisplayObject.mixin(accessibleTarget);
var KEY_CODE_TAB = 9;
var DIV_TOUCH_SIZE = 100;

@@ -128,3 +119,2 @@ var DIV_TOUCH_POS_X = 0;

var DIV_TOUCH_ZINDEX = 2;
var DIV_HOOK_SIZE = 1;

@@ -134,3 +124,2 @@ var DIV_HOOK_POS_X = -1000;

var DIV_HOOK_ZINDEX = 2;
/**

@@ -146,592 +135,469 @@ * The Accessibility manager recreates the ability to tab and have content read by screen readers.

* @class
* @memberof PIXI.accessibility
* @memberof PIXI
*/
var AccessibilityManager = function AccessibilityManager(renderer)
{
var AccessibilityManager = /** @class */ (function () {
/**
* @type {?HTMLElement}
* @private
* @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer
*/
this._hookDiv = null;
if (isMobile.tablet || isMobile.phone)
{
this.createTouchHook();
function AccessibilityManager(renderer) {
/**
* @type {?HTMLElement}
* @private
*/
this._hookDiv = null;
if (isMobile.tablet || isMobile.phone) {
this.createTouchHook();
}
// first we create a div that will sit over the PixiJS element. This is where the div overlays will go.
var div = document.createElement('div');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.position = 'absolute';
div.style.top = DIV_TOUCH_POS_X + "px";
div.style.left = DIV_TOUCH_POS_Y + "px";
div.style.zIndex = DIV_TOUCH_ZINDEX.toString();
/**
* This is the dom element that will sit over the PixiJS element. This is where the div overlays will go.
*
* @type {HTMLElement}
* @private
*/
this.div = div;
/**
* A simple pool for storing divs.
*
* @type {*}
* @private
*/
this.pool = [];
/**
* This is a tick used to check if an object is no longer being rendered.
*
* @type {Number}
* @private
*/
this.renderId = 0;
/**
* Setting this to true will visually show the divs.
*
* @type {boolean}
*/
this.debug = false;
/**
* The renderer this accessibility manager works for.
*
* @member {PIXI.AbstractRenderer}
*/
this.renderer = renderer;
/**
* The array of currently active accessible items.
*
* @member {Array<*>}
* @private
*/
this.children = [];
/**
* pre-bind the functions
*
* @type {Function}
* @private
*/
this._onKeyDown = this._onKeyDown.bind(this);
/**
* pre-bind the functions
*
* @type {Function}
* @private
*/
this._onMouseMove = this._onMouseMove.bind(this);
this._isActive = false;
this._isMobileAccessibility = false;
/**
* count to throttle div updates on android devices
* @type number
* @private
*/
this.androidUpdateCount = 0;
/**
* the frequency to update the div elements ()
* @private
*/
this.androidUpdateFrequency = 500; // 2fps
// let listen for tab.. once pressed we can fire up and show the accessibility layer
window.addEventListener('keydown', this._onKeyDown, false);
}
// first we create a div that will sit over the PixiJS element. This is where the div overlays will go.
var div = document.createElement('div');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.position = 'absolute';
div.style.top = DIV_TOUCH_POS_X + "px";
div.style.left = DIV_TOUCH_POS_Y + "px";
div.style.zIndex = DIV_TOUCH_ZINDEX;
Object.defineProperty(AccessibilityManager.prototype, "isActive", {
/**
* A flag
* @member {boolean}
* @readonly
*/
get: function () {
return this._isActive;
},
enumerable: false,
configurable: true
});
Object.defineProperty(AccessibilityManager.prototype, "isMobileAccessibility", {
/**
* A flag
* @member {boolean}
* @readonly
*/
get: function () {
return this._isMobileAccessibility;
},
enumerable: false,
configurable: true
});
/**
* This is the dom element that will sit over the PixiJS element. This is where the div overlays will go.
* Creates the touch hooks.
*
* @type {HTMLElement}
* @private
*/
this.div = div;
AccessibilityManager.prototype.createTouchHook = function () {
var _this = this;
var hookDiv = document.createElement('button');
hookDiv.style.width = DIV_HOOK_SIZE + "px";
hookDiv.style.height = DIV_HOOK_SIZE + "px";
hookDiv.style.position = 'absolute';
hookDiv.style.top = DIV_HOOK_POS_X + "px";
hookDiv.style.left = DIV_HOOK_POS_Y + "px";
hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString();
hookDiv.style.backgroundColor = '#FF0000';
hookDiv.title = 'select to enable accessability for this content';
hookDiv.addEventListener('focus', function () {
_this._isMobileAccessibility = true;
_this.activate();
_this.destroyTouchHook();
});
document.body.appendChild(hookDiv);
this._hookDiv = hookDiv;
};
/**
* A simple pool for storing divs.
* Destroys the touch hooks.
*
* @type {*}
* @private
*/
this.pool = [];
AccessibilityManager.prototype.destroyTouchHook = function () {
if (!this._hookDiv) {
return;
}
document.body.removeChild(this._hookDiv);
this._hookDiv = null;
};
/**
* This is a tick used to check if an object is no longer being rendered.
* Activating will cause the Accessibility layer to be shown.
* This is called when a user presses the tab key.
*
* @type {Number}
* @private
*/
this.renderId = 0;
AccessibilityManager.prototype.activate = function () {
if (this._isActive) {
return;
}
this._isActive = true;
window.document.addEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown, false);
// TODO: Remove casting when CanvasRenderer is converted
this.renderer.on('postrender', this.update, this);
if (this.renderer.view.parentNode) {
this.renderer.view.parentNode.appendChild(this.div);
}
};
/**
* Setting this to true will visually show the divs.
* Deactivating will cause the Accessibility layer to be hidden.
* This is called when a user moves the mouse.
*
* @type {boolean}
* @private
*/
this.debug = false;
AccessibilityManager.prototype.deactivate = function () {
if (!this._isActive || this._isMobileAccessibility) {
return;
}
this._isActive = false;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.addEventListener('keydown', this._onKeyDown, false);
// TODO: Remove casting when CanvasRenderer is converted
this.renderer.off('postrender', this.update);
if (this.div.parentNode) {
this.div.parentNode.removeChild(this.div);
}
};
/**
* The renderer this accessibility manager works for.
* This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
*
* @member {PIXI.AbstractRenderer}
* @private
* @param {PIXI.Container} displayObject - The DisplayObject to check.
*/
this.renderer = renderer;
AccessibilityManager.prototype.updateAccessibleObjects = function (displayObject) {
if (!displayObject.visible || !displayObject.accessibleChildren) {
return;
}
if (displayObject.accessible && displayObject.interactive) {
if (!displayObject._accessibleActive) {
this.addChild(displayObject);
}
displayObject.renderId = this.renderId;
}
var children = displayObject.children;
for (var i = 0; i < children.length; i++) {
this.updateAccessibleObjects(children[i]);
}
};
/**
* The array of currently active accessible items.
* Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
*
* @member {Array<*>}
* @private
*/
this.children = [];
AccessibilityManager.prototype.update = function () {
/* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,
* moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,
* so I am just running update every half a second, seems to fix it.
*/
var now = performance.now();
if (isMobile.android.device && now < this.androidUpdateCount) {
return;
}
this.androidUpdateCount = now + this.androidUpdateFrequency;
if (!this.renderer.renderingToScreen) {
return;
}
// update children...
if (this.renderer._lastObjectRendered) {
this.updateAccessibleObjects(this.renderer._lastObjectRendered);
}
// TODO: Remove casting when CanvasRenderer is converted
var rect = this.renderer.view.getBoundingClientRect();
var resolution = this.renderer.resolution;
var sx = (rect.width / this.renderer.width) * resolution;
var sy = (rect.height / this.renderer.height) * resolution;
var div = this.div;
div.style.left = rect.left + "px";
div.style.top = rect.top + "px";
div.style.width = this.renderer.width + "px";
div.style.height = this.renderer.height + "px";
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
if (child.renderId !== this.renderId) {
child._accessibleActive = false;
removeItems(this.children, i, 1);
this.div.removeChild(child._accessibleDiv);
this.pool.push(child._accessibleDiv);
child._accessibleDiv = null;
i--;
}
else {
// map div to display..
div = child._accessibleDiv;
var hitArea = child.hitArea;
var wt = child.worldTransform;
if (child.hitArea) {
div.style.left = (wt.tx + (hitArea.x * wt.a)) * sx + "px";
div.style.top = (wt.ty + (hitArea.y * wt.d)) * sy + "px";
div.style.width = hitArea.width * wt.a * sx + "px";
div.style.height = hitArea.height * wt.d * sy + "px";
}
else {
hitArea = child.getBounds();
this.capHitArea(hitArea);
div.style.left = hitArea.x * sx + "px";
div.style.top = hitArea.y * sy + "px";
div.style.width = hitArea.width * sx + "px";
div.style.height = hitArea.height * sy + "px";
// update button titles and hints if they exist and they've changed
if (div.title !== child.accessibleTitle && child.accessibleTitle !== null) {
div.title = child.accessibleTitle;
}
if (div.getAttribute('aria-label') !== child.accessibleHint
&& child.accessibleHint !== null) {
div.setAttribute('aria-label', child.accessibleHint);
}
}
// the title or index may have changed, if so lets update it!
if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex) {
div.title = child.accessibleTitle;
div.tabIndex = child.tabIndex;
if (this.debug)
{ this.updateDebugHTML(div); }
}
}
}
// increment the render id..
this.renderId++;
};
/**
* pre-bind the functions
* private function that will visually add the information to the
* accessability div
*
* @type {Function}
* @param {HTMLElement} div
*/
AccessibilityManager.prototype.updateDebugHTML = function (div) {
div.innerHTML = "type: " + div.type + "</br> title : " + div.title + "</br> tabIndex: " + div.tabIndex;
};
/**
* Adjust the hit area based on the bounds of a display object
*
* @param {PIXI.Rectangle} hitArea - Bounds of the child
*/
AccessibilityManager.prototype.capHitArea = function (hitArea) {
if (hitArea.x < 0) {
hitArea.width += hitArea.x;
hitArea.x = 0;
}
if (hitArea.y < 0) {
hitArea.height += hitArea.y;
hitArea.y = 0;
}
// TODO: Remove casting when CanvasRenderer is converted
if (hitArea.x + hitArea.width > this.renderer.width) {
hitArea.width = this.renderer.width - hitArea.x;
}
if (hitArea.y + hitArea.height > this.renderer.height) {
hitArea.height = this.renderer.height - hitArea.y;
}
};
/**
* Adds a DisplayObject to the accessibility manager
*
* @private
* @param {PIXI.DisplayObject} displayObject - The child to make accessible.
*/
this._onKeyDown = this._onKeyDown.bind(this);
AccessibilityManager.prototype.addChild = function (displayObject) {
// this.activate();
var div = this.pool.pop();
if (!div) {
div = document.createElement('button');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';
div.style.position = 'absolute';
div.style.zIndex = DIV_TOUCH_ZINDEX.toString();
div.style.borderStyle = 'none';
// ARIA attributes ensure that button title and hint updates are announced properly
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
// Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.
div.setAttribute('aria-live', 'off');
}
else {
div.setAttribute('aria-live', 'polite');
}
if (navigator.userAgent.match(/rv:.*Gecko\//)) {
// FireFox needs this to announce only the new button name
div.setAttribute('aria-relevant', 'additions');
}
else {
// required by IE, other browsers don't much care
div.setAttribute('aria-relevant', 'text');
}
div.addEventListener('click', this._onClick.bind(this));
div.addEventListener('focus', this._onFocus.bind(this));
div.addEventListener('focusout', this._onFocusOut.bind(this));
}
// set pointer events
div.style.pointerEvents = displayObject.accessiblePointerEvents;
// set the type, this defaults to button!
div.type = displayObject.accessibleType;
if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null) {
div.title = displayObject.accessibleTitle;
}
else if (!displayObject.accessibleHint
|| displayObject.accessibleHint === null) {
div.title = "displayObject " + displayObject.tabIndex;
}
if (displayObject.accessibleHint
&& displayObject.accessibleHint !== null) {
div.setAttribute('aria-label', displayObject.accessibleHint);
}
if (this.debug)
{ this.updateDebugHTML(div); }
displayObject._accessibleActive = true;
displayObject._accessibleDiv = div;
div.displayObject = displayObject;
this.children.push(displayObject);
this.div.appendChild(displayObject._accessibleDiv);
displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;
};
/**
* pre-bind the functions
* Maps the div button press to pixi's InteractionManager (click)
*
* @type {Function}
* @private
* @param {MouseEvent} e - The click event.
*/
this._onMouseMove = this._onMouseMove.bind(this);
AccessibilityManager.prototype._onClick = function (e) {
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'click', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'pointertap', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'tap', interactionManager.eventData);
};
/**
* A flag
* @type {boolean}
* @readonly
* Maps the div focus events to pixi's InteractionManager (mouseover)
*
* @private
* @param {FocusEvent} e - The focus event.
*/
this.isActive = false;
AccessibilityManager.prototype._onFocus = function (e) {
if (!e.target.getAttribute('aria-live')) {
e.target.setAttribute('aria-live', 'assertive');
}
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseover', interactionManager.eventData);
};
/**
* A flag
* @type {boolean}
* @readonly
* Maps the div focus events to pixi's InteractionManager (mouseout)
*
* @private
* @param {FocusEvent} e - The focusout event.
*/
this.isMobileAccessibility = false;
AccessibilityManager.prototype._onFocusOut = function (e) {
if (!e.target.getAttribute('aria-live')) {
e.target.setAttribute('aria-live', 'polite');
}
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseout', interactionManager.eventData);
};
/**
* count to throttle div updates on android devices
* @type number
* Is called when a key is pressed
*
* @private
* @param {KeyboardEvent} e - The keydown event.
*/
this.androidUpdateCount = 0;
AccessibilityManager.prototype._onKeyDown = function (e) {
if (e.keyCode !== KEY_CODE_TAB) {
return;
}
this.activate();
};
/**
* the frequency to update the div elements ()
* Is called when the mouse moves across the renderer element
*
* @private
* @param {MouseEvent} e - The mouse event.
*/
this.androidUpdateFrequency = 500; // 2fps
// let listen for tab.. once pressed we can fire up and show the accessibility layer
window.addEventListener('keydown', this._onKeyDown, false);
};
/**
* Creates the touch hooks.
*
* @private
*/
AccessibilityManager.prototype.createTouchHook = function createTouchHook ()
{
var this$1 = this;
var hookDiv = document.createElement('button');
hookDiv.style.width = DIV_HOOK_SIZE + "px";
hookDiv.style.height = DIV_HOOK_SIZE + "px";
hookDiv.style.position = 'absolute';
hookDiv.style.top = DIV_HOOK_POS_X + "px";
hookDiv.style.left = DIV_HOOK_POS_Y + "px";
hookDiv.style.zIndex = DIV_HOOK_ZINDEX;
hookDiv.style.backgroundColor = '#FF0000';
hookDiv.title = 'select to enable accessability for this content';
hookDiv.addEventListener('focus', function () {
this$1.isMobileAccessibility = true;
this$1.activate();
this$1.destroyTouchHook();
});
document.body.appendChild(hookDiv);
this._hookDiv = hookDiv;
};
/**
* Destroys the touch hooks.
*
* @private
*/
AccessibilityManager.prototype.destroyTouchHook = function destroyTouchHook ()
{
if (!this._hookDiv)
{
return;
}
document.body.removeChild(this._hookDiv);
this._hookDiv = null;
};
/**
* Activating will cause the Accessibility layer to be shown.
* This is called when a user presses the tab key.
*
* @private
*/
AccessibilityManager.prototype.activate = function activate ()
{
if (this.isActive)
{
return;
}
this.isActive = true;
window.document.addEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown, false);
this.renderer.on('postrender', this.update, this);
if (this.renderer.view.parentNode)
{
this.renderer.view.parentNode.appendChild(this.div);
}
};
/**
* Deactivating will cause the Accessibility layer to be hidden.
* This is called when a user moves the mouse.
*
* @private
*/
AccessibilityManager.prototype.deactivate = function deactivate ()
{
if (!this.isActive || this.isMobileAccessibility)
{
return;
}
this.isActive = false;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.addEventListener('keydown', this._onKeyDown, false);
this.renderer.off('postrender', this.update);
if (this.div.parentNode)
{
this.div.parentNode.removeChild(this.div);
}
};
/**
* This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
*
* @private
* @param {PIXI.Container} displayObject - The DisplayObject to check.
*/
AccessibilityManager.prototype.updateAccessibleObjects = function updateAccessibleObjects (displayObject)
{
if (!displayObject.visible || !displayObject.accessibleChildren)
{
return;
}
if (displayObject.accessible && displayObject.interactive)
{
if (!displayObject._accessibleActive)
{
this.addChild(displayObject);
AccessibilityManager.prototype._onMouseMove = function (e) {
if (e.movementX === 0 && e.movementY === 0) {
return;
}
this.deactivate();
};
/**
* Destroys the accessibility manager
*
*/
AccessibilityManager.prototype.destroy = function () {
this.destroyTouchHook();
this.div = null;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown);
this.pool = null;
this.children = null;
this.renderer = null;
};
return AccessibilityManager;
}());
displayObject.renderId = this.renderId;
}
var children = displayObject.children;
for (var i = 0; i < children.length; i++)
{
this.updateAccessibleObjects(children[i]);
}
};
/**
* Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
*
* @private
*/
AccessibilityManager.prototype.update = function update ()
{
/* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,
* moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,
* so I am just running update every half a second, seems to fix it.
*/
var now = performance.now();
if (isMobile.android.device && now < this.androidUpdateCount)
{
return;
}
this.androidUpdateCount = now + this.androidUpdateFrequency;
if (!this.renderer.renderingToScreen)
{
return;
}
// update children...
this.updateAccessibleObjects(this.renderer._lastObjectRendered);
var rect = this.renderer.view.getBoundingClientRect();
var resolution = this.renderer.resolution;
var sx = (rect.width / this.renderer.width) * resolution;
var sy = (rect.height / this.renderer.height) * resolution;
var div = this.div;
div.style.left = (rect.left) + "px";
div.style.top = (rect.top) + "px";
div.style.width = (this.renderer.width) + "px";
div.style.height = (this.renderer.height) + "px";
for (var i = 0; i < this.children.length; i++)
{
var child = this.children[i];
if (child.renderId !== this.renderId)
{
child._accessibleActive = false;
removeItems(this.children, i, 1);
this.div.removeChild(child._accessibleDiv);
this.pool.push(child._accessibleDiv);
child._accessibleDiv = null;
i--;
}
else
{
// map div to display..
div = child._accessibleDiv;
var hitArea = child.hitArea;
var wt = child.worldTransform;
if (child.hitArea)
{
div.style.left = ((wt.tx + (hitArea.x * wt.a)) * sx) + "px";
div.style.top = ((wt.ty + (hitArea.y * wt.d)) * sy) + "px";
div.style.width = (hitArea.width * wt.a * sx) + "px";
div.style.height = (hitArea.height * wt.d * sy) + "px";
}
else
{
hitArea = child.getBounds();
this.capHitArea(hitArea);
div.style.left = (hitArea.x * sx) + "px";
div.style.top = (hitArea.y * sy) + "px";
div.style.width = (hitArea.width * sx) + "px";
div.style.height = (hitArea.height * sy) + "px";
// update button titles and hints if they exist and they've changed
if (div.title !== child.accessibleTitle && child.accessibleTitle !== null)
{
div.title = child.accessibleTitle;
}
if (div.getAttribute('aria-label') !== child.accessibleHint
&& child.accessibleHint !== null)
{
div.setAttribute('aria-label', child.accessibleHint);
}
}
// the title or index may have changed, if so lets update it!
if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex)
{
div.title = child.accessibleTitle;
div.tabIndex = child.tabIndex;
if (this.debug) { this.updateDebugHTML(div); }
}
}
}
// increment the render id..
this.renderId++;
};
/**
* private function that will visually add the information to the
* accessability div
*
* @param {HTMLDivElement} div
*/
AccessibilityManager.prototype.updateDebugHTML = function updateDebugHTML (div)
{
div.innerHTML = "type: " + (div.type) + "</br> title : " + (div.title) + "</br> tabIndex: " + (div.tabIndex);
};
/**
* Adjust the hit area based on the bounds of a display object
*
* @param {PIXI.Rectangle} hitArea - Bounds of the child
*/
AccessibilityManager.prototype.capHitArea = function capHitArea (hitArea)
{
if (hitArea.x < 0)
{
hitArea.width += hitArea.x;
hitArea.x = 0;
}
if (hitArea.y < 0)
{
hitArea.height += hitArea.y;
hitArea.y = 0;
}
if (hitArea.x + hitArea.width > this.renderer.width)
{
hitArea.width = this.renderer.width - hitArea.x;
}
if (hitArea.y + hitArea.height > this.renderer.height)
{
hitArea.height = this.renderer.height - hitArea.y;
}
};
/**
* Adds a DisplayObject to the accessibility manager
*
* @private
* @param {PIXI.DisplayObject} displayObject - The child to make accessible.
*/
AccessibilityManager.prototype.addChild = function addChild (displayObject)
{
//this.activate();
var div = this.pool.pop();
if (!div)
{
div = document.createElement('button');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';
div.style.position = 'absolute';
div.style.zIndex = DIV_TOUCH_ZINDEX;
div.style.borderStyle = 'none';
// ARIA attributes ensure that button title and hint updates are announced properly
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1)
{
// Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.
div.setAttribute('aria-live', 'off');
}
else
{
div.setAttribute('aria-live', 'polite');
}
if (navigator.userAgent.match(/rv:.*Gecko\//))
{
// FireFox needs this to announce only the new button name
div.setAttribute('aria-relevant', 'additions');
}
else
{
// required by IE, other browsers don't much care
div.setAttribute('aria-relevant', 'text');
}
div.addEventListener('click', this._onClick.bind(this));
div.addEventListener('focus', this._onFocus.bind(this));
div.addEventListener('focusout', this._onFocusOut.bind(this));
}
// set pointer events
div.style.pointerEvents = displayObject.accessiblePointerEvents;
// set the type, this defaults to button!
div.type = displayObject.accessibleType;
if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null)
{
div.title = displayObject.accessibleTitle;
}
else if (!displayObject.accessibleHint
|| displayObject.accessibleHint === null)
{
div.title = "displayObject " + (displayObject.tabIndex);
}
if (displayObject.accessibleHint
&& displayObject.accessibleHint !== null)
{
div.setAttribute('aria-label', displayObject.accessibleHint);
}
if (this.debug) { this.updateDebugHTML(div); }
displayObject._accessibleActive = true;
displayObject._accessibleDiv = div;
div.displayObject = displayObject;
this.children.push(displayObject);
this.div.appendChild(displayObject._accessibleDiv);
displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;
};
/**
* Maps the div button press to pixi's InteractionManager (click)
*
* @private
* @param {MouseEvent} e - The click event.
*/
AccessibilityManager.prototype._onClick = function _onClick (e)
{
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'click', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'pointertap', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'tap', interactionManager.eventData);
};
/**
* Maps the div focus events to pixi's InteractionManager (mouseover)
*
* @private
* @param {FocusEvent} e - The focus event.
*/
AccessibilityManager.prototype._onFocus = function _onFocus (e)
{
if (!e.target.getAttribute('aria-live', 'off'))
{
e.target.setAttribute('aria-live', 'assertive');
}
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseover', interactionManager.eventData);
};
/**
* Maps the div focus events to pixi's InteractionManager (mouseout)
*
* @private
* @param {FocusEvent} e - The focusout event.
*/
AccessibilityManager.prototype._onFocusOut = function _onFocusOut (e)
{
if (!e.target.getAttribute('aria-live', 'off'))
{
e.target.setAttribute('aria-live', 'polite');
}
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseout', interactionManager.eventData);
};
/**
* Is called when a key is pressed
*
* @private
* @param {KeyboardEvent} e - The keydown event.
*/
AccessibilityManager.prototype._onKeyDown = function _onKeyDown (e)
{
if (e.keyCode !== KEY_CODE_TAB)
{
return;
}
this.activate();
};
/**
* Is called when the mouse moves across the renderer element
*
* @private
* @param {MouseEvent} e - The mouse event.
*/
AccessibilityManager.prototype._onMouseMove = function _onMouseMove (e)
{
if (e.movementX === 0 && e.movementY === 0)
{
return;
}
this.deactivate();
};
/**
* Destroys the accessibility manager
*
*/
AccessibilityManager.prototype.destroy = function destroy ()
{
this.destroyTouchHook();
this.div = null;
for (var i = 0; i < this.children.length; i++)
{
this.children[i].div = null;
}
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown);
this.pool = null;
this.children = null;
this.renderer = null;
};
/**
* This namespace contains an accessibility plugin for allowing interaction via the keyboard.
*
* Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
* See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.Renderer#plugins}.
* @namespace PIXI.accessibility
*/
export { AccessibilityManager, accessibleTarget };
//# sourceMappingURL=accessibility.es.js.map
/*!
* @pixi/accessibility - v5.2.4
* Compiled Sun, 03 May 2020 22:38:52 UTC
* @pixi/accessibility - v5.3.0
* Compiled Thu, 18 Jun 2020 23:27:40 UTC
*

@@ -12,12 +12,12 @@ * @pixi/accessibility is licensed under the MIT License.

var display = require('@pixi/display');
var utils = require('@pixi/utils');
var display = require('@pixi/display');
/**
* Default property values of accessible objects
* used by {@link PIXI.accessibility.AccessibilityManager}.
* used by {@link PIXI.AccessibilityManager}.
*
* @private
* @function accessibleTarget
* @memberof PIXI.accessibility
* @memberof PIXI
* @type {Object}

@@ -29,3 +29,3 @@ * @example

* MyObject.prototype,
* PIXI.accessibility.accessibleTarget
* PIXI.accessibleTarget
* );

@@ -42,3 +42,2 @@ */

accessible: false,
/**

@@ -52,3 +51,2 @@ * Sets the title attribute of the shadow div

accessibleTitle: null,
/**

@@ -61,3 +59,2 @@ * Sets the aria-label attribute of the shadow div

accessibleHint: null,
/**

@@ -70,3 +67,2 @@ * @member {number}

tabIndex: 0,
/**

@@ -78,3 +74,2 @@ * @member {boolean}

_accessibleActive: false,
/**

@@ -85,4 +80,3 @@ * @member {boolean}

*/
_accessibleDiv: false,
_accessibleDiv: null,
/**

@@ -97,3 +91,2 @@ * Specify the type of div the accessible layer is. Screen readers treat the element differently

accessibleType: 'button',
/**

@@ -108,3 +101,2 @@ * Specify the pointer-events the accessible div will use

accessiblePointerEvents: 'auto',
/**

@@ -119,2 +111,3 @@ * Setting to false will prevent any children inside this container to

accessibleChildren: true,
renderId: -1,
};

@@ -124,5 +117,3 @@

display.DisplayObject.mixin(accessibleTarget);
var KEY_CODE_TAB = 9;
var DIV_TOUCH_SIZE = 100;

@@ -132,3 +123,2 @@ var DIV_TOUCH_POS_X = 0;

var DIV_TOUCH_ZINDEX = 2;
var DIV_HOOK_SIZE = 1;

@@ -138,3 +128,2 @@ var DIV_HOOK_POS_X = -1000;

var DIV_HOOK_ZINDEX = 2;
/**

@@ -150,593 +139,470 @@ * The Accessibility manager recreates the ability to tab and have content read by screen readers.

* @class
* @memberof PIXI.accessibility
* @memberof PIXI
*/
var AccessibilityManager = function AccessibilityManager(renderer)
{
var AccessibilityManager = /** @class */ (function () {
/**
* @type {?HTMLElement}
* @private
* @param {PIXI.CanvasRenderer|PIXI.Renderer} renderer - A reference to the current renderer
*/
this._hookDiv = null;
if (utils.isMobile.tablet || utils.isMobile.phone)
{
this.createTouchHook();
function AccessibilityManager(renderer) {
/**
* @type {?HTMLElement}
* @private
*/
this._hookDiv = null;
if (utils.isMobile.tablet || utils.isMobile.phone) {
this.createTouchHook();
}
// first we create a div that will sit over the PixiJS element. This is where the div overlays will go.
var div = document.createElement('div');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.position = 'absolute';
div.style.top = DIV_TOUCH_POS_X + "px";
div.style.left = DIV_TOUCH_POS_Y + "px";
div.style.zIndex = DIV_TOUCH_ZINDEX.toString();
/**
* This is the dom element that will sit over the PixiJS element. This is where the div overlays will go.
*
* @type {HTMLElement}
* @private
*/
this.div = div;
/**
* A simple pool for storing divs.
*
* @type {*}
* @private
*/
this.pool = [];
/**
* This is a tick used to check if an object is no longer being rendered.
*
* @type {Number}
* @private
*/
this.renderId = 0;
/**
* Setting this to true will visually show the divs.
*
* @type {boolean}
*/
this.debug = false;
/**
* The renderer this accessibility manager works for.
*
* @member {PIXI.AbstractRenderer}
*/
this.renderer = renderer;
/**
* The array of currently active accessible items.
*
* @member {Array<*>}
* @private
*/
this.children = [];
/**
* pre-bind the functions
*
* @type {Function}
* @private
*/
this._onKeyDown = this._onKeyDown.bind(this);
/**
* pre-bind the functions
*
* @type {Function}
* @private
*/
this._onMouseMove = this._onMouseMove.bind(this);
this._isActive = false;
this._isMobileAccessibility = false;
/**
* count to throttle div updates on android devices
* @type number
* @private
*/
this.androidUpdateCount = 0;
/**
* the frequency to update the div elements ()
* @private
*/
this.androidUpdateFrequency = 500; // 2fps
// let listen for tab.. once pressed we can fire up and show the accessibility layer
window.addEventListener('keydown', this._onKeyDown, false);
}
// first we create a div that will sit over the PixiJS element. This is where the div overlays will go.
var div = document.createElement('div');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.position = 'absolute';
div.style.top = DIV_TOUCH_POS_X + "px";
div.style.left = DIV_TOUCH_POS_Y + "px";
div.style.zIndex = DIV_TOUCH_ZINDEX;
Object.defineProperty(AccessibilityManager.prototype, "isActive", {
/**
* A flag
* @member {boolean}
* @readonly
*/
get: function () {
return this._isActive;
},
enumerable: false,
configurable: true
});
Object.defineProperty(AccessibilityManager.prototype, "isMobileAccessibility", {
/**
* A flag
* @member {boolean}
* @readonly
*/
get: function () {
return this._isMobileAccessibility;
},
enumerable: false,
configurable: true
});
/**
* This is the dom element that will sit over the PixiJS element. This is where the div overlays will go.
* Creates the touch hooks.
*
* @type {HTMLElement}
* @private
*/
this.div = div;
AccessibilityManager.prototype.createTouchHook = function () {
var _this = this;
var hookDiv = document.createElement('button');
hookDiv.style.width = DIV_HOOK_SIZE + "px";
hookDiv.style.height = DIV_HOOK_SIZE + "px";
hookDiv.style.position = 'absolute';
hookDiv.style.top = DIV_HOOK_POS_X + "px";
hookDiv.style.left = DIV_HOOK_POS_Y + "px";
hookDiv.style.zIndex = DIV_HOOK_ZINDEX.toString();
hookDiv.style.backgroundColor = '#FF0000';
hookDiv.title = 'select to enable accessability for this content';
hookDiv.addEventListener('focus', function () {
_this._isMobileAccessibility = true;
_this.activate();
_this.destroyTouchHook();
});
document.body.appendChild(hookDiv);
this._hookDiv = hookDiv;
};
/**
* A simple pool for storing divs.
* Destroys the touch hooks.
*
* @type {*}
* @private
*/
this.pool = [];
AccessibilityManager.prototype.destroyTouchHook = function () {
if (!this._hookDiv) {
return;
}
document.body.removeChild(this._hookDiv);
this._hookDiv = null;
};
/**
* This is a tick used to check if an object is no longer being rendered.
* Activating will cause the Accessibility layer to be shown.
* This is called when a user presses the tab key.
*
* @type {Number}
* @private
*/
this.renderId = 0;
AccessibilityManager.prototype.activate = function () {
if (this._isActive) {
return;
}
this._isActive = true;
window.document.addEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown, false);
// TODO: Remove casting when CanvasRenderer is converted
this.renderer.on('postrender', this.update, this);
if (this.renderer.view.parentNode) {
this.renderer.view.parentNode.appendChild(this.div);
}
};
/**
* Setting this to true will visually show the divs.
* Deactivating will cause the Accessibility layer to be hidden.
* This is called when a user moves the mouse.
*
* @type {boolean}
* @private
*/
this.debug = false;
AccessibilityManager.prototype.deactivate = function () {
if (!this._isActive || this._isMobileAccessibility) {
return;
}
this._isActive = false;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.addEventListener('keydown', this._onKeyDown, false);
// TODO: Remove casting when CanvasRenderer is converted
this.renderer.off('postrender', this.update);
if (this.div.parentNode) {
this.div.parentNode.removeChild(this.div);
}
};
/**
* The renderer this accessibility manager works for.
* This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
*
* @member {PIXI.AbstractRenderer}
* @private
* @param {PIXI.Container} displayObject - The DisplayObject to check.
*/
this.renderer = renderer;
AccessibilityManager.prototype.updateAccessibleObjects = function (displayObject) {
if (!displayObject.visible || !displayObject.accessibleChildren) {
return;
}
if (displayObject.accessible && displayObject.interactive) {
if (!displayObject._accessibleActive) {
this.addChild(displayObject);
}
displayObject.renderId = this.renderId;
}
var children = displayObject.children;
for (var i = 0; i < children.length; i++) {
this.updateAccessibleObjects(children[i]);
}
};
/**
* The array of currently active accessible items.
* Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
*
* @member {Array<*>}
* @private
*/
this.children = [];
AccessibilityManager.prototype.update = function () {
/* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,
* moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,
* so I am just running update every half a second, seems to fix it.
*/
var now = performance.now();
if (utils.isMobile.android.device && now < this.androidUpdateCount) {
return;
}
this.androidUpdateCount = now + this.androidUpdateFrequency;
if (!this.renderer.renderingToScreen) {
return;
}
// update children...
if (this.renderer._lastObjectRendered) {
this.updateAccessibleObjects(this.renderer._lastObjectRendered);
}
// TODO: Remove casting when CanvasRenderer is converted
var rect = this.renderer.view.getBoundingClientRect();
var resolution = this.renderer.resolution;
var sx = (rect.width / this.renderer.width) * resolution;
var sy = (rect.height / this.renderer.height) * resolution;
var div = this.div;
div.style.left = rect.left + "px";
div.style.top = rect.top + "px";
div.style.width = this.renderer.width + "px";
div.style.height = this.renderer.height + "px";
for (var i = 0; i < this.children.length; i++) {
var child = this.children[i];
if (child.renderId !== this.renderId) {
child._accessibleActive = false;
utils.removeItems(this.children, i, 1);
this.div.removeChild(child._accessibleDiv);
this.pool.push(child._accessibleDiv);
child._accessibleDiv = null;
i--;
}
else {
// map div to display..
div = child._accessibleDiv;
var hitArea = child.hitArea;
var wt = child.worldTransform;
if (child.hitArea) {
div.style.left = (wt.tx + (hitArea.x * wt.a)) * sx + "px";
div.style.top = (wt.ty + (hitArea.y * wt.d)) * sy + "px";
div.style.width = hitArea.width * wt.a * sx + "px";
div.style.height = hitArea.height * wt.d * sy + "px";
}
else {
hitArea = child.getBounds();
this.capHitArea(hitArea);
div.style.left = hitArea.x * sx + "px";
div.style.top = hitArea.y * sy + "px";
div.style.width = hitArea.width * sx + "px";
div.style.height = hitArea.height * sy + "px";
// update button titles and hints if they exist and they've changed
if (div.title !== child.accessibleTitle && child.accessibleTitle !== null) {
div.title = child.accessibleTitle;
}
if (div.getAttribute('aria-label') !== child.accessibleHint
&& child.accessibleHint !== null) {
div.setAttribute('aria-label', child.accessibleHint);
}
}
// the title or index may have changed, if so lets update it!
if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex) {
div.title = child.accessibleTitle;
div.tabIndex = child.tabIndex;
if (this.debug)
{ this.updateDebugHTML(div); }
}
}
}
// increment the render id..
this.renderId++;
};
/**
* pre-bind the functions
* private function that will visually add the information to the
* accessability div
*
* @type {Function}
* @param {HTMLElement} div
*/
AccessibilityManager.prototype.updateDebugHTML = function (div) {
div.innerHTML = "type: " + div.type + "</br> title : " + div.title + "</br> tabIndex: " + div.tabIndex;
};
/**
* Adjust the hit area based on the bounds of a display object
*
* @param {PIXI.Rectangle} hitArea - Bounds of the child
*/
AccessibilityManager.prototype.capHitArea = function (hitArea) {
if (hitArea.x < 0) {
hitArea.width += hitArea.x;
hitArea.x = 0;
}
if (hitArea.y < 0) {
hitArea.height += hitArea.y;
hitArea.y = 0;
}
// TODO: Remove casting when CanvasRenderer is converted
if (hitArea.x + hitArea.width > this.renderer.width) {
hitArea.width = this.renderer.width - hitArea.x;
}
if (hitArea.y + hitArea.height > this.renderer.height) {
hitArea.height = this.renderer.height - hitArea.y;
}
};
/**
* Adds a DisplayObject to the accessibility manager
*
* @private
* @param {PIXI.DisplayObject} displayObject - The child to make accessible.
*/
this._onKeyDown = this._onKeyDown.bind(this);
AccessibilityManager.prototype.addChild = function (displayObject) {
// this.activate();
var div = this.pool.pop();
if (!div) {
div = document.createElement('button');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';
div.style.position = 'absolute';
div.style.zIndex = DIV_TOUCH_ZINDEX.toString();
div.style.borderStyle = 'none';
// ARIA attributes ensure that button title and hint updates are announced properly
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1) {
// Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.
div.setAttribute('aria-live', 'off');
}
else {
div.setAttribute('aria-live', 'polite');
}
if (navigator.userAgent.match(/rv:.*Gecko\//)) {
// FireFox needs this to announce only the new button name
div.setAttribute('aria-relevant', 'additions');
}
else {
// required by IE, other browsers don't much care
div.setAttribute('aria-relevant', 'text');
}
div.addEventListener('click', this._onClick.bind(this));
div.addEventListener('focus', this._onFocus.bind(this));
div.addEventListener('focusout', this._onFocusOut.bind(this));
}
// set pointer events
div.style.pointerEvents = displayObject.accessiblePointerEvents;
// set the type, this defaults to button!
div.type = displayObject.accessibleType;
if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null) {
div.title = displayObject.accessibleTitle;
}
else if (!displayObject.accessibleHint
|| displayObject.accessibleHint === null) {
div.title = "displayObject " + displayObject.tabIndex;
}
if (displayObject.accessibleHint
&& displayObject.accessibleHint !== null) {
div.setAttribute('aria-label', displayObject.accessibleHint);
}
if (this.debug)
{ this.updateDebugHTML(div); }
displayObject._accessibleActive = true;
displayObject._accessibleDiv = div;
div.displayObject = displayObject;
this.children.push(displayObject);
this.div.appendChild(displayObject._accessibleDiv);
displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;
};
/**
* pre-bind the functions
* Maps the div button press to pixi's InteractionManager (click)
*
* @type {Function}
* @private
* @param {MouseEvent} e - The click event.
*/
this._onMouseMove = this._onMouseMove.bind(this);
AccessibilityManager.prototype._onClick = function (e) {
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'click', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'pointertap', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'tap', interactionManager.eventData);
};
/**
* A flag
* @type {boolean}
* @readonly
* Maps the div focus events to pixi's InteractionManager (mouseover)
*
* @private
* @param {FocusEvent} e - The focus event.
*/
this.isActive = false;
AccessibilityManager.prototype._onFocus = function (e) {
if (!e.target.getAttribute('aria-live')) {
e.target.setAttribute('aria-live', 'assertive');
}
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseover', interactionManager.eventData);
};
/**
* A flag
* @type {boolean}
* @readonly
* Maps the div focus events to pixi's InteractionManager (mouseout)
*
* @private
* @param {FocusEvent} e - The focusout event.
*/
this.isMobileAccessibility = false;
AccessibilityManager.prototype._onFocusOut = function (e) {
if (!e.target.getAttribute('aria-live')) {
e.target.setAttribute('aria-live', 'polite');
}
// TODO: Remove casting when CanvasRenderer is converted
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseout', interactionManager.eventData);
};
/**
* count to throttle div updates on android devices
* @type number
* Is called when a key is pressed
*
* @private
* @param {KeyboardEvent} e - The keydown event.
*/
this.androidUpdateCount = 0;
AccessibilityManager.prototype._onKeyDown = function (e) {
if (e.keyCode !== KEY_CODE_TAB) {
return;
}
this.activate();
};
/**
* the frequency to update the div elements ()
* Is called when the mouse moves across the renderer element
*
* @private
* @param {MouseEvent} e - The mouse event.
*/
this.androidUpdateFrequency = 500; // 2fps
// let listen for tab.. once pressed we can fire up and show the accessibility layer
window.addEventListener('keydown', this._onKeyDown, false);
};
/**
* Creates the touch hooks.
*
* @private
*/
AccessibilityManager.prototype.createTouchHook = function createTouchHook ()
{
var this$1 = this;
var hookDiv = document.createElement('button');
hookDiv.style.width = DIV_HOOK_SIZE + "px";
hookDiv.style.height = DIV_HOOK_SIZE + "px";
hookDiv.style.position = 'absolute';
hookDiv.style.top = DIV_HOOK_POS_X + "px";
hookDiv.style.left = DIV_HOOK_POS_Y + "px";
hookDiv.style.zIndex = DIV_HOOK_ZINDEX;
hookDiv.style.backgroundColor = '#FF0000';
hookDiv.title = 'select to enable accessability for this content';
hookDiv.addEventListener('focus', function () {
this$1.isMobileAccessibility = true;
this$1.activate();
this$1.destroyTouchHook();
});
document.body.appendChild(hookDiv);
this._hookDiv = hookDiv;
};
/**
* Destroys the touch hooks.
*
* @private
*/
AccessibilityManager.prototype.destroyTouchHook = function destroyTouchHook ()
{
if (!this._hookDiv)
{
return;
}
document.body.removeChild(this._hookDiv);
this._hookDiv = null;
};
/**
* Activating will cause the Accessibility layer to be shown.
* This is called when a user presses the tab key.
*
* @private
*/
AccessibilityManager.prototype.activate = function activate ()
{
if (this.isActive)
{
return;
}
this.isActive = true;
window.document.addEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown, false);
this.renderer.on('postrender', this.update, this);
if (this.renderer.view.parentNode)
{
this.renderer.view.parentNode.appendChild(this.div);
}
};
/**
* Deactivating will cause the Accessibility layer to be hidden.
* This is called when a user moves the mouse.
*
* @private
*/
AccessibilityManager.prototype.deactivate = function deactivate ()
{
if (!this.isActive || this.isMobileAccessibility)
{
return;
}
this.isActive = false;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.addEventListener('keydown', this._onKeyDown, false);
this.renderer.off('postrender', this.update);
if (this.div.parentNode)
{
this.div.parentNode.removeChild(this.div);
}
};
/**
* This recursive function will run through the scene graph and add any new accessible objects to the DOM layer.
*
* @private
* @param {PIXI.Container} displayObject - The DisplayObject to check.
*/
AccessibilityManager.prototype.updateAccessibleObjects = function updateAccessibleObjects (displayObject)
{
if (!displayObject.visible || !displayObject.accessibleChildren)
{
return;
}
if (displayObject.accessible && displayObject.interactive)
{
if (!displayObject._accessibleActive)
{
this.addChild(displayObject);
AccessibilityManager.prototype._onMouseMove = function (e) {
if (e.movementX === 0 && e.movementY === 0) {
return;
}
this.deactivate();
};
/**
* Destroys the accessibility manager
*
*/
AccessibilityManager.prototype.destroy = function () {
this.destroyTouchHook();
this.div = null;
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown);
this.pool = null;
this.children = null;
this.renderer = null;
};
return AccessibilityManager;
}());
displayObject.renderId = this.renderId;
}
var children = displayObject.children;
for (var i = 0; i < children.length; i++)
{
this.updateAccessibleObjects(children[i]);
}
};
/**
* Before each render this function will ensure that all divs are mapped correctly to their DisplayObjects.
*
* @private
*/
AccessibilityManager.prototype.update = function update ()
{
/* On Android default web browser, tab order seems to be calculated by position rather than tabIndex,
* moving buttons can cause focus to flicker between two buttons making it hard/impossible to navigate,
* so I am just running update every half a second, seems to fix it.
*/
var now = performance.now();
if (utils.isMobile.android.device && now < this.androidUpdateCount)
{
return;
}
this.androidUpdateCount = now + this.androidUpdateFrequency;
if (!this.renderer.renderingToScreen)
{
return;
}
// update children...
this.updateAccessibleObjects(this.renderer._lastObjectRendered);
var rect = this.renderer.view.getBoundingClientRect();
var resolution = this.renderer.resolution;
var sx = (rect.width / this.renderer.width) * resolution;
var sy = (rect.height / this.renderer.height) * resolution;
var div = this.div;
div.style.left = (rect.left) + "px";
div.style.top = (rect.top) + "px";
div.style.width = (this.renderer.width) + "px";
div.style.height = (this.renderer.height) + "px";
for (var i = 0; i < this.children.length; i++)
{
var child = this.children[i];
if (child.renderId !== this.renderId)
{
child._accessibleActive = false;
utils.removeItems(this.children, i, 1);
this.div.removeChild(child._accessibleDiv);
this.pool.push(child._accessibleDiv);
child._accessibleDiv = null;
i--;
}
else
{
// map div to display..
div = child._accessibleDiv;
var hitArea = child.hitArea;
var wt = child.worldTransform;
if (child.hitArea)
{
div.style.left = ((wt.tx + (hitArea.x * wt.a)) * sx) + "px";
div.style.top = ((wt.ty + (hitArea.y * wt.d)) * sy) + "px";
div.style.width = (hitArea.width * wt.a * sx) + "px";
div.style.height = (hitArea.height * wt.d * sy) + "px";
}
else
{
hitArea = child.getBounds();
this.capHitArea(hitArea);
div.style.left = (hitArea.x * sx) + "px";
div.style.top = (hitArea.y * sy) + "px";
div.style.width = (hitArea.width * sx) + "px";
div.style.height = (hitArea.height * sy) + "px";
// update button titles and hints if they exist and they've changed
if (div.title !== child.accessibleTitle && child.accessibleTitle !== null)
{
div.title = child.accessibleTitle;
}
if (div.getAttribute('aria-label') !== child.accessibleHint
&& child.accessibleHint !== null)
{
div.setAttribute('aria-label', child.accessibleHint);
}
}
// the title or index may have changed, if so lets update it!
if (child.accessibleTitle !== div.title || child.tabIndex !== div.tabIndex)
{
div.title = child.accessibleTitle;
div.tabIndex = child.tabIndex;
if (this.debug) { this.updateDebugHTML(div); }
}
}
}
// increment the render id..
this.renderId++;
};
/**
* private function that will visually add the information to the
* accessability div
*
* @param {HTMLDivElement} div
*/
AccessibilityManager.prototype.updateDebugHTML = function updateDebugHTML (div)
{
div.innerHTML = "type: " + (div.type) + "</br> title : " + (div.title) + "</br> tabIndex: " + (div.tabIndex);
};
/**
* Adjust the hit area based on the bounds of a display object
*
* @param {PIXI.Rectangle} hitArea - Bounds of the child
*/
AccessibilityManager.prototype.capHitArea = function capHitArea (hitArea)
{
if (hitArea.x < 0)
{
hitArea.width += hitArea.x;
hitArea.x = 0;
}
if (hitArea.y < 0)
{
hitArea.height += hitArea.y;
hitArea.y = 0;
}
if (hitArea.x + hitArea.width > this.renderer.width)
{
hitArea.width = this.renderer.width - hitArea.x;
}
if (hitArea.y + hitArea.height > this.renderer.height)
{
hitArea.height = this.renderer.height - hitArea.y;
}
};
/**
* Adds a DisplayObject to the accessibility manager
*
* @private
* @param {PIXI.DisplayObject} displayObject - The child to make accessible.
*/
AccessibilityManager.prototype.addChild = function addChild (displayObject)
{
//this.activate();
var div = this.pool.pop();
if (!div)
{
div = document.createElement('button');
div.style.width = DIV_TOUCH_SIZE + "px";
div.style.height = DIV_TOUCH_SIZE + "px";
div.style.backgroundColor = this.debug ? 'rgba(255,255,255,0.5)' : 'transparent';
div.style.position = 'absolute';
div.style.zIndex = DIV_TOUCH_ZINDEX;
div.style.borderStyle = 'none';
// ARIA attributes ensure that button title and hint updates are announced properly
if (navigator.userAgent.toLowerCase().indexOf('chrome') > -1)
{
// Chrome doesn't need aria-live to work as intended; in fact it just gets more confused.
div.setAttribute('aria-live', 'off');
}
else
{
div.setAttribute('aria-live', 'polite');
}
if (navigator.userAgent.match(/rv:.*Gecko\//))
{
// FireFox needs this to announce only the new button name
div.setAttribute('aria-relevant', 'additions');
}
else
{
// required by IE, other browsers don't much care
div.setAttribute('aria-relevant', 'text');
}
div.addEventListener('click', this._onClick.bind(this));
div.addEventListener('focus', this._onFocus.bind(this));
div.addEventListener('focusout', this._onFocusOut.bind(this));
}
// set pointer events
div.style.pointerEvents = displayObject.accessiblePointerEvents;
// set the type, this defaults to button!
div.type = displayObject.accessibleType;
if (displayObject.accessibleTitle && displayObject.accessibleTitle !== null)
{
div.title = displayObject.accessibleTitle;
}
else if (!displayObject.accessibleHint
|| displayObject.accessibleHint === null)
{
div.title = "displayObject " + (displayObject.tabIndex);
}
if (displayObject.accessibleHint
&& displayObject.accessibleHint !== null)
{
div.setAttribute('aria-label', displayObject.accessibleHint);
}
if (this.debug) { this.updateDebugHTML(div); }
displayObject._accessibleActive = true;
displayObject._accessibleDiv = div;
div.displayObject = displayObject;
this.children.push(displayObject);
this.div.appendChild(displayObject._accessibleDiv);
displayObject._accessibleDiv.tabIndex = displayObject.tabIndex;
};
/**
* Maps the div button press to pixi's InteractionManager (click)
*
* @private
* @param {MouseEvent} e - The click event.
*/
AccessibilityManager.prototype._onClick = function _onClick (e)
{
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'click', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'pointertap', interactionManager.eventData);
interactionManager.dispatchEvent(e.target.displayObject, 'tap', interactionManager.eventData);
};
/**
* Maps the div focus events to pixi's InteractionManager (mouseover)
*
* @private
* @param {FocusEvent} e - The focus event.
*/
AccessibilityManager.prototype._onFocus = function _onFocus (e)
{
if (!e.target.getAttribute('aria-live', 'off'))
{
e.target.setAttribute('aria-live', 'assertive');
}
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseover', interactionManager.eventData);
};
/**
* Maps the div focus events to pixi's InteractionManager (mouseout)
*
* @private
* @param {FocusEvent} e - The focusout event.
*/
AccessibilityManager.prototype._onFocusOut = function _onFocusOut (e)
{
if (!e.target.getAttribute('aria-live', 'off'))
{
e.target.setAttribute('aria-live', 'polite');
}
var interactionManager = this.renderer.plugins.interaction;
interactionManager.dispatchEvent(e.target.displayObject, 'mouseout', interactionManager.eventData);
};
/**
* Is called when a key is pressed
*
* @private
* @param {KeyboardEvent} e - The keydown event.
*/
AccessibilityManager.prototype._onKeyDown = function _onKeyDown (e)
{
if (e.keyCode !== KEY_CODE_TAB)
{
return;
}
this.activate();
};
/**
* Is called when the mouse moves across the renderer element
*
* @private
* @param {MouseEvent} e - The mouse event.
*/
AccessibilityManager.prototype._onMouseMove = function _onMouseMove (e)
{
if (e.movementX === 0 && e.movementY === 0)
{
return;
}
this.deactivate();
};
/**
* Destroys the accessibility manager
*
*/
AccessibilityManager.prototype.destroy = function destroy ()
{
this.destroyTouchHook();
this.div = null;
for (var i = 0; i < this.children.length; i++)
{
this.children[i].div = null;
}
window.document.removeEventListener('mousemove', this._onMouseMove, true);
window.removeEventListener('keydown', this._onKeyDown);
this.pool = null;
this.children = null;
this.renderer = null;
};
/**
* This namespace contains an accessibility plugin for allowing interaction via the keyboard.
*
* Do not instantiate this plugin directly. It is available from the `renderer.plugins` property.
* See {@link PIXI.CanvasRenderer#plugins} or {@link PIXI.Renderer#plugins}.
* @namespace PIXI.accessibility
*/
exports.AccessibilityManager = AccessibilityManager;
exports.accessibleTarget = accessibleTarget;
//# sourceMappingURL=accessibility.js.map
{
"name": "@pixi/accessibility",
"version": "5.2.4",
"version": "5.3.0",
"main": "lib/accessibility.js",
"module": "lib/accessibility.es.js",
"bundle": "dist/accessibility.js",
"namespace": "PIXI.accessibility",
"description": "Accessibility Plugin for visually impared users",

@@ -28,10 +27,10 @@ "author": "Mat Groves",

"dependencies": {
"@pixi/core": "5.2.4",
"@pixi/display": "5.2.4",
"@pixi/utils": "5.2.4"
"@pixi/core": "5.3.0",
"@pixi/display": "5.3.0",
"@pixi/utils": "5.3.0"
},
"devDependencies": {
"@pixi/canvas-renderer": "5.2.4"
"@pixi/canvas-renderer": "5.3.0"
},
"gitHead": "71c6b3b2061af4a4f3a95a265d46e933b8befc2c"
"gitHead": "a9b7b32a9c0aeb3d9c42ef04b2c2a39be1cd0880"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc