tupali/librerias/gantt/code/es-modules/modules/accessibility/focusBorder.js

249 lines
8.5 KiB
JavaScript

/* *
*
* (c) 2009-2020 Øystein Moseng
*
* Extend SVG and Chart classes with focus border capabilities.
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
import H from '../../parts/Globals.js';
import U from '../../parts/Utilities.js';
var addEvent = U.addEvent, extend = U.extend, pick = U.pick;
/* eslint-disable no-invalid-this, valid-jsdoc */
// Attributes that trigger a focus border update
var svgElementBorderUpdateTriggers = [
'x', 'y', 'transform', 'width', 'height', 'r', 'd', 'stroke-width'
];
/**
* Add hook to destroy focus border if SVG element is destroyed, unless
* hook already exists.
*
* @param el Element to add destroy hook to
*/
function addDestroyFocusBorderHook(el) {
if (el.focusBorderDestroyHook) {
return;
}
var origDestroy = el.destroy;
el.destroy = function () {
var _a, _b;
(_b = (_a = el.focusBorder) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a);
return origDestroy.apply(el, arguments);
};
el.focusBorderDestroyHook = origDestroy;
}
/**
* Remove hook from SVG element added by addDestroyFocusBorderHook, if
* existing.
*
* @param el Element to remove destroy hook from
*/
function removeDestroyFocusBorderHook(el) {
if (!el.focusBorderDestroyHook) {
return;
}
el.destroy = el.focusBorderDestroyHook;
delete el.focusBorderDestroyHook;
}
/**
* Add hooks to update the focus border of an element when the element
* size/position is updated, unless already added.
*
* @param el Element to add update hooks to
* @param updateParams Parameters to pass through to addFocusBorder when updating.
*/
function addUpdateFocusBorderHooks(el) {
var updateParams = [];
for (var _i = 1; _i < arguments.length; _i++) {
updateParams[_i - 1] = arguments[_i];
}
if (el.focusBorderUpdateHooks) {
return;
}
el.focusBorderUpdateHooks = {};
svgElementBorderUpdateTriggers.forEach(function (trigger) {
var setterKey = trigger + 'Setter';
var origSetter = el[setterKey] || el._defaultSetter;
el.focusBorderUpdateHooks[setterKey] = origSetter;
el[setterKey] = function () {
var ret = origSetter.apply(el, arguments);
el.addFocusBorder.apply(el, updateParams);
return ret;
};
});
}
/**
* Remove hooks from SVG element added by addUpdateFocusBorderHooks, if
* existing.
*
* @param el Element to remove update hooks from
*/
function removeUpdateFocusBorderHooks(el) {
if (!el.focusBorderUpdateHooks) {
return;
}
Object.keys(el.focusBorderUpdateHooks).forEach(function (setterKey) {
var origSetter = el.focusBorderUpdateHooks[setterKey];
if (origSetter === el._defaultSetter) {
delete el[setterKey];
}
else {
el[setterKey] = origSetter;
}
});
delete el.focusBorderUpdateHooks;
}
/*
* Add focus border functionality to SVGElements. Draws a new rect on top of
* element around its bounding box. This is used by multiple components.
*/
extend(H.SVGElement.prototype, {
/**
* @private
* @function Highcharts.SVGElement#addFocusBorder
*
* @param {number} margin
*
* @param {Highcharts.CSSObject} style
*/
addFocusBorder: function (margin, style) {
// Allow updating by just adding new border
if (this.focusBorder) {
this.removeFocusBorder();
}
// Add the border rect
var bb = this.getBBox(), pad = pick(margin, 3);
bb.x += this.translateX ? this.translateX : 0;
bb.y += this.translateY ? this.translateY : 0;
var borderPosX = bb.x - pad, borderPosY = bb.y - pad, borderWidth = bb.width + 2 * pad, borderHeight = bb.height + 2 * pad;
// For text elements, apply x and y offset, #11397.
/**
* @private
* @function
*
* @param {Highcharts.SVGElement} text
*
* @return {TextAnchorCorrectionObject}
*/
function getTextAnchorCorrection(text) {
var posXCorrection = 0, posYCorrection = 0;
if (text.attr('text-anchor') === 'middle') {
posXCorrection = H.isFirefox && text.rotation ? 0.25 : 0.5;
posYCorrection = H.isFirefox && !text.rotation ? 0.75 : 0.5;
}
else if (!text.rotation) {
posYCorrection = 0.75;
}
else {
posXCorrection = 0.25;
}
return {
x: posXCorrection,
y: posYCorrection
};
}
if (this.element.nodeName === 'text' || this.isLabel) {
var isRotated = !!this.rotation, correction = !this.isLabel ? getTextAnchorCorrection(this) :
{
x: isRotated ? 1 : 0,
y: 0
};
borderPosX = +this.attr('x') - (bb.width * correction.x) - pad;
borderPosY = +this.attr('y') - (bb.height * correction.y) - pad;
if (this.isLabel && isRotated) {
var temp = borderWidth;
borderWidth = borderHeight;
borderHeight = temp;
borderPosX = +this.attr('x') - (bb.height * correction.x) - pad;
borderPosY = +this.attr('y') - (bb.width * correction.y) - pad;
}
}
this.focusBorder = this.renderer.rect(borderPosX, borderPosY, borderWidth, borderHeight, parseInt((style && style.borderRadius || 0).toString(), 10))
.addClass('highcharts-focus-border')
.attr({
zIndex: 99
})
.add(this.parentGroup);
if (!this.renderer.styledMode) {
this.focusBorder.attr({
stroke: style && style.stroke,
'stroke-width': style && style.strokeWidth
});
}
addUpdateFocusBorderHooks(this, margin, style);
addDestroyFocusBorderHook(this);
},
/**
* @private
* @function Highcharts.SVGElement#removeFocusBorder
*/
removeFocusBorder: function () {
removeUpdateFocusBorderHooks(this);
removeDestroyFocusBorderHook(this);
if (this.focusBorder) {
this.focusBorder.destroy();
delete this.focusBorder;
}
}
});
/**
* Redraws the focus border on the currently focused element.
*
* @private
* @function Highcharts.Chart#renderFocusBorder
*/
H.Chart.prototype.renderFocusBorder = function () {
var focusElement = this.focusElement, focusBorderOptions = this.options.accessibility.keyboardNavigation.focusBorder;
if (focusElement) {
focusElement.removeFocusBorder();
if (focusBorderOptions.enabled) {
focusElement.addFocusBorder(focusBorderOptions.margin, {
stroke: focusBorderOptions.style.color,
strokeWidth: focusBorderOptions.style.lineWidth,
borderRadius: focusBorderOptions.style.borderRadius
});
}
}
};
/**
* Set chart's focus to an SVGElement. Calls focus() on it, and draws the focus
* border. This is used by multiple components.
*
* @private
* @function Highcharts.Chart#setFocusToElement
*
* @param {Highcharts.SVGElement} svgElement
* Element to draw the border around.
*
* @param {SVGDOMElement|HTMLDOMElement} [focusElement]
* If supplied, it draws the border around svgElement and sets the focus
* to focusElement.
*/
H.Chart.prototype.setFocusToElement = function (svgElement, focusElement) {
var focusBorderOptions = this.options.accessibility.keyboardNavigation.focusBorder, browserFocusElement = focusElement || svgElement.element;
// Set browser focus if possible
if (browserFocusElement &&
browserFocusElement.focus) {
// If there is no focusin-listener, add one to work around Edge issue
// where Narrator is not reading out points despite calling focus().
if (!(browserFocusElement.hcEvents &&
browserFocusElement.hcEvents.focusin)) {
addEvent(browserFocusElement, 'focusin', function () { });
}
browserFocusElement.focus();
// Hide default focus ring
if (focusBorderOptions.hideBrowserFocusOutline) {
browserFocusElement.style.outline = 'none';
}
}
if (this.focusElement) {
this.focusElement.removeFocusBorder();
}
this.focusElement = svgElement;
this.renderFocusBorder();
};