Carga
This commit is contained in:
2025-04-17 00:35:33 -06:00
parent 4977462629
commit 67fc72aed5
1333 changed files with 1077639 additions and 0 deletions

View File

@@ -0,0 +1,550 @@
/* *
*
* (c) 2009-2021 Øystein Moseng
*
* Accessibility component for chart info region and table.
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
'use strict';
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
import A11yI18n from '../A11yI18n.js';
import AccessibilityComponent from '../AccessibilityComponent.js';
import Announcer from '../Utils/Announcer.js';
import AnnotationsA11y from './AnnotationsA11y.js';
var getAnnotationsInfoHTML = AnnotationsA11y.getAnnotationsInfoHTML;
import AST from '../../Core/Renderer/HTML/AST.js';
import CU from '../Utils/ChartUtilities.js';
var getAxisDescription = CU.getAxisDescription, getAxisRangeDescription = CU.getAxisRangeDescription, getChartTitle = CU.getChartTitle, unhideChartElementFromAT = CU.unhideChartElementFromAT;
import F from '../../Core/FormatUtilities.js';
var format = F.format;
import H from '../../Core/Globals.js';
var doc = H.doc;
import HU from '../Utils/HTMLUtilities.js';
var addClass = HU.addClass, getElement = HU.getElement, getHeadingTagNameForElement = HU.getHeadingTagNameForElement, stripHTMLTagsFromString = HU.stripHTMLTagsFromString, visuallyHideElement = HU.visuallyHideElement;
import U from '../../Core/Utilities.js';
var attr = U.attr, pick = U.pick;
/* *
*
* Functions
*
* */
/* eslint-disable valid-jsdoc */
/**
* @private
*/
function getTableSummary(chart) {
return chart.langFormat('accessibility.table.tableSummary', { chart: chart });
}
/**
* @private
*/
function getTypeDescForMapChart(chart, formatContext) {
return formatContext.mapTitle ?
chart.langFormat('accessibility.chartTypes.mapTypeDescription', formatContext) :
chart.langFormat('accessibility.chartTypes.unknownMap', formatContext);
}
/**
* @private
*/
function getTypeDescForCombinationChart(chart, formatContext) {
return chart.langFormat('accessibility.chartTypes.combinationChart', formatContext);
}
/**
* @private
*/
function getTypeDescForEmptyChart(chart, formatContext) {
return chart.langFormat('accessibility.chartTypes.emptyChart', formatContext);
}
/**
* @private
*/
function buildTypeDescriptionFromSeries(chart, types, context) {
var firstType = types[0], typeExplaination = chart.langFormat('accessibility.seriesTypeDescriptions.' + firstType, context), multi = chart.series && chart.series.length < 2 ? 'Single' : 'Multiple';
return (chart.langFormat('accessibility.chartTypes.' + firstType + multi, context) ||
chart.langFormat('accessibility.chartTypes.default' + multi, context)) + (typeExplaination ? ' ' + typeExplaination : '');
}
/**
* Return simplified explaination of chart type. Some types will not be
* familiar to most users, but in those cases we try to add an explaination
* of the type.
*
* @private
* @function Highcharts.Chart#getTypeDescription
* @param {Array<string>} types The series types in this chart.
* @return {string} The text description of the chart type.
*/
function getTypeDescription(chart, types) {
var firstType = types[0], firstSeries = chart.series && chart.series[0] || {}, mapTitle = chart.mapView && chart.mapView.geoMap &&
chart.mapView.geoMap.title, formatContext = {
numSeries: chart.series.length,
numPoints: firstSeries.points && firstSeries.points.length,
chart: chart,
mapTitle: mapTitle
};
if (!firstType) {
return getTypeDescForEmptyChart(chart, formatContext);
}
if (firstType === 'map') {
return getTypeDescForMapChart(chart, formatContext);
}
if (chart.types.length > 1) {
return getTypeDescForCombinationChart(chart, formatContext);
}
return buildTypeDescriptionFromSeries(chart, types, formatContext);
}
/**
* @private
*/
function stripEmptyHTMLTags(str) {
return str.replace(/<(\w+)[^>]*?>\s*<\/\1>/g, '');
}
/* *
*
* Class
*
* */
/**
* The InfoRegionsComponent class
*
* @private
* @class
* @name Highcharts.InfoRegionsComponent
*/
var InfoRegionsComponent = /** @class */ (function (_super) {
__extends(InfoRegionsComponent, _super);
function InfoRegionsComponent() {
/* *
*
* Properties
*
* */
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.announcer = void 0;
_this.screenReaderSections = {};
return _this;
}
/* *
*
* Functions
*
* */
/* eslint-disable valid-jsdoc */
/**
* Init the component
* @private
*/
InfoRegionsComponent.prototype.init = function () {
var chart = this.chart;
var component = this;
this.initRegionsDefinitions();
this.addEvent(chart, 'aftergetTableAST', function (e) {
component.onDataTableCreated(e);
});
this.addEvent(chart, 'afterViewData', function (tableDiv) {
component.dataTableDiv = tableDiv;
// Use small delay to give browsers & AT time to register new table
setTimeout(function () {
component.focusDataTable();
}, 300);
});
this.announcer = new Announcer(chart, 'assertive');
};
/**
* @private
*/
InfoRegionsComponent.prototype.initRegionsDefinitions = function () {
var component = this;
this.screenReaderSections = {
before: {
element: null,
buildContent: function (chart) {
var formatter = chart.options.accessibility
.screenReaderSection.beforeChartFormatter;
return formatter ? formatter(chart) :
component.defaultBeforeChartFormatter(chart);
},
insertIntoDOM: function (el, chart) {
chart.renderTo.insertBefore(el, chart.renderTo.firstChild);
},
afterInserted: function () {
if (typeof component.sonifyButtonId !== 'undefined') {
component.initSonifyButton(component.sonifyButtonId);
}
if (typeof component.dataTableButtonId !== 'undefined') {
component.initDataTableButton(component.dataTableButtonId);
}
}
},
after: {
element: null,
buildContent: function (chart) {
var formatter = chart.options.accessibility
.screenReaderSection
.afterChartFormatter;
return formatter ? formatter(chart) :
component.defaultAfterChartFormatter();
},
insertIntoDOM: function (el, chart) {
chart.renderTo.insertBefore(el, chart.container.nextSibling);
},
afterInserted: function () {
if (component.chart.accessibility) {
component.chart.accessibility
.keyboardNavigation.updateExitAnchor(); // #15986
}
}
}
};
};
/**
* Called on chart render. Have to update the sections on render, in order
* to get a11y info from series.
*/
InfoRegionsComponent.prototype.onChartRender = function () {
var component = this;
this.linkedDescriptionElement = this.getLinkedDescriptionElement();
this.setLinkedDescriptionAttrs();
Object.keys(this.screenReaderSections).forEach(function (regionKey) {
component.updateScreenReaderSection(regionKey);
});
};
/**
* @private
*/
InfoRegionsComponent.prototype.getLinkedDescriptionElement = function () {
var chartOptions = this.chart.options, linkedDescOption = chartOptions.accessibility.linkedDescription;
if (!linkedDescOption) {
return;
}
if (typeof linkedDescOption !== 'string') {
return linkedDescOption;
}
var query = format(linkedDescOption, this.chart), queryMatch = doc.querySelectorAll(query);
if (queryMatch.length === 1) {
return queryMatch[0];
}
};
/**
* @private
*/
InfoRegionsComponent.prototype.setLinkedDescriptionAttrs = function () {
var el = this.linkedDescriptionElement;
if (el) {
el.setAttribute('aria-hidden', 'true');
addClass(el, 'highcharts-linked-description');
}
};
/**
* @private
* @param {string} regionKey
* The name/key of the region to update
*/
InfoRegionsComponent.prototype.updateScreenReaderSection = function (regionKey) {
var chart = this.chart;
var region = this.screenReaderSections[regionKey];
var content = region.buildContent(chart);
var sectionDiv = region.element = (region.element || this.createElement('div'));
var hiddenDiv = (sectionDiv.firstChild || this.createElement('div'));
if (content) {
this.setScreenReaderSectionAttribs(sectionDiv, regionKey);
AST.setElementHTML(hiddenDiv, content);
sectionDiv.appendChild(hiddenDiv);
region.insertIntoDOM(sectionDiv, chart);
if (chart.styledMode) {
addClass(hiddenDiv, 'highcharts-visually-hidden');
}
else {
visuallyHideElement(hiddenDiv);
}
unhideChartElementFromAT(chart, hiddenDiv);
if (region.afterInserted) {
region.afterInserted();
}
}
else {
if (sectionDiv.parentNode) {
sectionDiv.parentNode.removeChild(sectionDiv);
}
region.element = null;
}
};
/**
* Apply a11y attributes to a screen reader info section
* @private
* @param {Highcharts.HTMLDOMElement} sectionDiv The section element
* @param {string} regionKey Name/key of the region we are setting attrs for
*/
InfoRegionsComponent.prototype.setScreenReaderSectionAttribs = function (sectionDiv, regionKey) {
var chart = this.chart, labelText = chart.langFormat('accessibility.screenReaderSection.' + regionKey +
'RegionLabel', { chart: chart, chartTitle: getChartTitle(chart) }), sectionId = "highcharts-screen-reader-region-".concat(regionKey, "-").concat(chart.index);
attr(sectionDiv, {
id: sectionId,
'aria-label': labelText || void 0
});
// Sections are wrapped to be positioned relatively to chart in case
// elements inside are tabbed to.
sectionDiv.style.position = 'relative';
if (labelText) {
sectionDiv.setAttribute('role', chart.options.accessibility.landmarkVerbosity === 'all' ?
'region' : 'group');
}
};
/**
* @private
*/
InfoRegionsComponent.prototype.defaultBeforeChartFormatter = function () {
var chart = this.chart, format = chart.options.accessibility.screenReaderSection
.beforeChartFormat;
if (!format) {
return '';
}
var axesDesc = this.getAxesDescription(), shouldHaveSonifyBtn = (chart.sonify &&
chart.options.sonification &&
chart.options.sonification.enabled), sonifyButtonId = 'highcharts-a11y-sonify-data-btn-' +
chart.index, dataTableButtonId = 'hc-linkto-highcharts-data-table-' +
chart.index, annotationsList = getAnnotationsInfoHTML(chart), annotationsTitleStr = chart.langFormat('accessibility.screenReaderSection.annotations.heading', { chart: chart }), context = {
headingTagName: getHeadingTagNameForElement(chart.renderTo),
chartTitle: getChartTitle(chart),
typeDescription: this.getTypeDescriptionText(),
chartSubtitle: this.getSubtitleText(),
chartLongdesc: this.getLongdescText(),
xAxisDescription: axesDesc.xAxis,
yAxisDescription: axesDesc.yAxis,
playAsSoundButton: shouldHaveSonifyBtn ?
this.getSonifyButtonText(sonifyButtonId) : '',
viewTableButton: chart.getCSV ?
this.getDataTableButtonText(dataTableButtonId) : '',
annotationsTitle: annotationsList ? annotationsTitleStr : '',
annotationsList: annotationsList
}, formattedString = A11yI18n.i18nFormat(format, context, chart);
this.dataTableButtonId = dataTableButtonId;
this.sonifyButtonId = sonifyButtonId;
return stripEmptyHTMLTags(formattedString);
};
/**
* @private
*/
InfoRegionsComponent.prototype.defaultAfterChartFormatter = function () {
var chart = this.chart;
var format = chart.options.accessibility.screenReaderSection
.afterChartFormat;
if (!format) {
return '';
}
var context = { endOfChartMarker: this.getEndOfChartMarkerText() };
var formattedString = A11yI18n.i18nFormat(format, context, chart);
return stripEmptyHTMLTags(formattedString);
};
/**
* @private
*/
InfoRegionsComponent.prototype.getLinkedDescription = function () {
var el = this.linkedDescriptionElement, content = el && el.innerHTML || '';
return stripHTMLTagsFromString(content);
};
/**
* @private
*/
InfoRegionsComponent.prototype.getLongdescText = function () {
var chartOptions = this.chart.options, captionOptions = chartOptions.caption, captionText = captionOptions && captionOptions.text, linkedDescription = this.getLinkedDescription();
return (chartOptions.accessibility.description ||
linkedDescription ||
captionText ||
'');
};
/**
* @private
*/
InfoRegionsComponent.prototype.getTypeDescriptionText = function () {
var chart = this.chart;
return chart.types ?
chart.options.accessibility.typeDescription ||
getTypeDescription(chart, chart.types) : '';
};
/**
* @private
*/
InfoRegionsComponent.prototype.getDataTableButtonText = function (buttonId) {
var chart = this.chart, buttonText = chart.langFormat('accessibility.table.viewAsDataTableButtonText', { chart: chart, chartTitle: getChartTitle(chart) });
return '<button id="' + buttonId + '">' + buttonText + '</button>';
};
/**
* @private
*/
InfoRegionsComponent.prototype.getSonifyButtonText = function (buttonId) {
var chart = this.chart;
if (chart.options.sonification &&
chart.options.sonification.enabled === false) {
return '';
}
var buttonText = chart.langFormat('accessibility.sonification.playAsSoundButtonText', { chart: chart, chartTitle: getChartTitle(chart) });
return '<button id="' + buttonId + '">' + buttonText + '</button>';
};
/**
* @private
*/
InfoRegionsComponent.prototype.getSubtitleText = function () {
var subtitle = (this.chart.options.subtitle);
return stripHTMLTagsFromString(subtitle && subtitle.text || '');
};
/**
* @private
*/
InfoRegionsComponent.prototype.getEndOfChartMarkerText = function () {
var chart = this.chart, markerText = chart.langFormat('accessibility.screenReaderSection.endOfChartMarker', { chart: chart }), id = 'highcharts-end-of-chart-marker-' + chart.index;
return '<div id="' + id + '">' + markerText + '</div>';
};
/**
* @private
* @param {Highcharts.Dictionary<string>} e
*/
InfoRegionsComponent.prototype.onDataTableCreated = function (e) {
var chart = this.chart;
if (chart.options.accessibility.enabled) {
if (this.viewDataTableButton) {
this.viewDataTableButton.setAttribute('aria-expanded', 'true');
}
var attributes = e.tree.attributes || {};
attributes.tabindex = -1;
attributes.summary = getTableSummary(chart);
e.tree.attributes = attributes;
}
};
/**
* @private
*/
InfoRegionsComponent.prototype.focusDataTable = function () {
var tableDiv = this.dataTableDiv, table = tableDiv && tableDiv.getElementsByTagName('table')[0];
if (table && table.focus) {
table.focus();
}
};
/**
* @private
* @param {string} sonifyButtonId
*/
InfoRegionsComponent.prototype.initSonifyButton = function (sonifyButtonId) {
var _this = this;
var el = this.sonifyButton = getElement(sonifyButtonId);
var chart = this.chart;
var defaultHandler = function (e) {
if (el) {
el.setAttribute('aria-hidden', 'true');
el.setAttribute('aria-label', '');
}
e.preventDefault();
e.stopPropagation();
var announceMsg = chart.langFormat('accessibility.sonification.playAsSoundClickAnnouncement', { chart: chart });
_this.announcer.announce(announceMsg);
setTimeout(function () {
if (el) {
el.removeAttribute('aria-hidden');
el.removeAttribute('aria-label');
}
if (chart.sonify) {
chart.sonify();
}
}, 1000); // Delay to let screen reader speak the button press
};
if (el && chart) {
el.setAttribute('tabindex', -1);
el.onclick = function (e) {
var onPlayAsSoundClick = (chart.options.accessibility &&
chart.options.accessibility.screenReaderSection
.onPlayAsSoundClick);
(onPlayAsSoundClick || defaultHandler).call(this, e, chart);
};
}
};
/**
* Set attribs and handlers for default viewAsDataTable button if exists.
* @private
* @param {string} tableButtonId
*/
InfoRegionsComponent.prototype.initDataTableButton = function (tableButtonId) {
var el = this.viewDataTableButton = getElement(tableButtonId), chart = this.chart, tableId = tableButtonId.replace('hc-linkto-', '');
if (el) {
attr(el, {
tabindex: -1,
'aria-expanded': !!getElement(tableId)
});
el.onclick = chart.options.accessibility
.screenReaderSection.onViewDataTableClick ||
function () {
chart.viewData();
};
}
};
/**
* Return object with text description of each of the chart's axes.
* @private
*/
InfoRegionsComponent.prototype.getAxesDescription = function () {
var chart = this.chart, shouldDescribeColl = function (collectionKey, defaultCondition) {
var axes = chart[collectionKey];
return axes.length > 1 || axes[0] &&
pick(axes[0].options.accessibility &&
axes[0].options.accessibility.enabled, defaultCondition);
}, hasNoMap = !!chart.types &&
chart.types.indexOf('map') < 0 &&
chart.types.indexOf('treemap') < 0 &&
chart.types.indexOf('tilemap') < 0, hasCartesian = !!chart.hasCartesianSeries, showXAxes = shouldDescribeColl('xAxis', !chart.angular && hasCartesian && hasNoMap), showYAxes = shouldDescribeColl('yAxis', hasCartesian && hasNoMap), desc = {};
if (showXAxes) {
desc.xAxis = this.getAxisDescriptionText('xAxis');
}
if (showYAxes) {
desc.yAxis = this.getAxisDescriptionText('yAxis');
}
return desc;
};
/**
* @private
*/
InfoRegionsComponent.prototype.getAxisDescriptionText = function (collectionKey) {
var chart = this.chart;
var axes = chart[collectionKey];
return chart.langFormat('accessibility.axis.' + collectionKey + 'Description' + (axes.length > 1 ? 'Plural' : 'Singular'), {
chart: chart,
names: axes.map(function (axis) {
return getAxisDescription(axis);
}),
ranges: axes.map(function (axis) {
return getAxisRangeDescription(axis);
}),
numAxes: axes.length
});
};
/**
* Remove component traces
*/
InfoRegionsComponent.prototype.destroy = function () {
if (this.announcer) {
this.announcer.destroy();
}
};
return InfoRegionsComponent;
}(AccessibilityComponent));
/* *
*
* Default Export
*
* */
export default InfoRegionsComponent;