Carga
Carga
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
/* *
|
||||
*
|
||||
* (c) 2009-2021 Øystein Moseng
|
||||
*
|
||||
* Create announcer to speak messages to screen readers and other AT.
|
||||
*
|
||||
* License: www.highcharts.com/license
|
||||
*
|
||||
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
||||
*
|
||||
* */
|
||||
'use strict';
|
||||
import AST from '../../Core/Renderer/HTML/AST.js';
|
||||
import DOMElementProvider from './DOMElementProvider.js';
|
||||
import H from '../../Core/Globals.js';
|
||||
var doc = H.doc;
|
||||
import HU from './HTMLUtilities.js';
|
||||
var addClass = HU.addClass, visuallyHideElement = HU.visuallyHideElement;
|
||||
import U from '../../Core/Utilities.js';
|
||||
var attr = U.attr;
|
||||
/* *
|
||||
*
|
||||
* Class
|
||||
*
|
||||
* */
|
||||
var Announcer = /** @class */ (function () {
|
||||
/* *
|
||||
*
|
||||
* Constructor
|
||||
*
|
||||
* */
|
||||
function Announcer(chart, type) {
|
||||
this.chart = chart;
|
||||
this.domElementProvider = new DOMElementProvider();
|
||||
this.announceRegion = this.addAnnounceRegion(type);
|
||||
}
|
||||
/* *
|
||||
*
|
||||
* Functions
|
||||
*
|
||||
* */
|
||||
Announcer.prototype.destroy = function () {
|
||||
this.domElementProvider.destroyCreatedElements();
|
||||
};
|
||||
Announcer.prototype.announce = function (message) {
|
||||
var _this = this;
|
||||
AST.setElementHTML(this.announceRegion, message);
|
||||
// Delete contents after a little while to avoid user finding the live
|
||||
// region in the DOM.
|
||||
if (this.clearAnnouncementRegionTimer) {
|
||||
clearTimeout(this.clearAnnouncementRegionTimer);
|
||||
}
|
||||
this.clearAnnouncementRegionTimer = setTimeout(function () {
|
||||
_this.announceRegion.innerHTML = AST.emptyHTML;
|
||||
delete _this.clearAnnouncementRegionTimer;
|
||||
}, 1000);
|
||||
};
|
||||
Announcer.prototype.addAnnounceRegion = function (type) {
|
||||
var chartContainer = (this.chart.announcerContainer || this.createAnnouncerContainer()), div = this.domElementProvider.createElement('div');
|
||||
attr(div, {
|
||||
'aria-hidden': false,
|
||||
'aria-live': type
|
||||
});
|
||||
if (this.chart.styledMode) {
|
||||
addClass(div, 'highcharts-visually-hidden');
|
||||
}
|
||||
else {
|
||||
visuallyHideElement(div);
|
||||
}
|
||||
chartContainer.appendChild(div);
|
||||
return div;
|
||||
};
|
||||
Announcer.prototype.createAnnouncerContainer = function () {
|
||||
var chart = this.chart, container = doc.createElement('div');
|
||||
attr(container, {
|
||||
'aria-hidden': false,
|
||||
'class': 'highcharts-announcer-container'
|
||||
});
|
||||
container.style.position = 'relative';
|
||||
chart.renderTo.insertBefore(container, chart.renderTo.firstChild);
|
||||
chart.announcerContainer = container;
|
||||
return container;
|
||||
};
|
||||
return Announcer;
|
||||
}());
|
||||
/* *
|
||||
*
|
||||
* Default Export
|
||||
*
|
||||
* */
|
||||
export default Announcer;
|
||||
@@ -0,0 +1,299 @@
|
||||
/* *
|
||||
*
|
||||
* (c) 2009-2021 Øystein Moseng
|
||||
*
|
||||
* Utils for dealing with charts.
|
||||
*
|
||||
* License: www.highcharts.com/license
|
||||
*
|
||||
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
||||
*
|
||||
* */
|
||||
'use strict';
|
||||
import H from '../../Core/Globals.js';
|
||||
var doc = H.doc;
|
||||
import HU from './HTMLUtilities.js';
|
||||
var stripHTMLTags = HU.stripHTMLTagsFromString;
|
||||
import U from '../../Core/Utilities.js';
|
||||
var defined = U.defined, find = U.find, fireEvent = U.fireEvent;
|
||||
/* *
|
||||
*
|
||||
* Functions
|
||||
*
|
||||
* */
|
||||
/* eslint-disable valid-jsdoc */
|
||||
/**
|
||||
* Fire an event on an element that is either wrapped by Highcharts,
|
||||
* or a DOM element.
|
||||
* @private
|
||||
*/
|
||||
function fireEventOnWrappedOrUnwrappedElement(el, eventObject) {
|
||||
var type = eventObject.type;
|
||||
var hcEvents = el.hcEvents;
|
||||
if ((doc.createEvent) &&
|
||||
(el.dispatchEvent || el.fireEvent)) {
|
||||
if (el.dispatchEvent) {
|
||||
el.dispatchEvent(eventObject);
|
||||
}
|
||||
else {
|
||||
el.fireEvent(type, eventObject);
|
||||
}
|
||||
}
|
||||
else if (hcEvents && hcEvents[type]) {
|
||||
fireEvent(el, type, eventObject);
|
||||
}
|
||||
else if (el.element) {
|
||||
fireEventOnWrappedOrUnwrappedElement(el.element, eventObject);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function getChartTitle(chart) {
|
||||
return stripHTMLTags(chart.options.title.text ||
|
||||
chart.langFormat('accessibility.defaultChartTitle', { chart: chart }));
|
||||
}
|
||||
/**
|
||||
* Return string with the axis name/title.
|
||||
* @private
|
||||
*/
|
||||
function getAxisDescription(axis) {
|
||||
return axis && (axis.userOptions && axis.userOptions.accessibility &&
|
||||
axis.userOptions.accessibility.description ||
|
||||
axis.axisTitle && axis.axisTitle.textStr ||
|
||||
axis.options.id ||
|
||||
axis.categories && 'categories' ||
|
||||
axis.dateTime && 'Time' ||
|
||||
'values');
|
||||
}
|
||||
/**
|
||||
* Return string with text description of the axis range.
|
||||
* @private
|
||||
* @param {Highcharts.Axis} axis
|
||||
* The axis to get range desc of.
|
||||
* @return {string}
|
||||
* A string with the range description for the axis.
|
||||
*/
|
||||
function getAxisRangeDescription(axis) {
|
||||
var axisOptions = axis.options || {};
|
||||
// Handle overridden range description
|
||||
if (axisOptions.accessibility &&
|
||||
typeof axisOptions.accessibility.rangeDescription !== 'undefined') {
|
||||
return axisOptions.accessibility.rangeDescription;
|
||||
}
|
||||
// Handle category axes
|
||||
if (axis.categories) {
|
||||
return getCategoryAxisRangeDesc(axis);
|
||||
}
|
||||
// Use time range, not from-to?
|
||||
if (axis.dateTime && (axis.min === 0 || axis.dataMin === 0)) {
|
||||
return getAxisTimeLengthDesc(axis);
|
||||
}
|
||||
// Just use from and to.
|
||||
// We have the range and the unit to use, find the desc format
|
||||
return getAxisFromToDescription(axis);
|
||||
}
|
||||
/**
|
||||
* Describe the range of a category axis.
|
||||
* @private
|
||||
*/
|
||||
function getCategoryAxisRangeDesc(axis) {
|
||||
var chart = axis.chart;
|
||||
if (axis.dataMax && axis.dataMin) {
|
||||
return chart.langFormat('accessibility.axis.rangeCategories', {
|
||||
chart: chart,
|
||||
axis: axis,
|
||||
numCategories: axis.dataMax - axis.dataMin + 1
|
||||
});
|
||||
}
|
||||
return '';
|
||||
}
|
||||
/**
|
||||
* Describe the length of the time window shown on an axis.
|
||||
* @private
|
||||
*/
|
||||
function getAxisTimeLengthDesc(axis) {
|
||||
var chart = axis.chart, range = {}, min = axis.dataMin || axis.min || 0, max = axis.dataMax || axis.max || 0;
|
||||
var rangeUnit = 'Seconds';
|
||||
range.Seconds = (max - min) / 1000;
|
||||
range.Minutes = range.Seconds / 60;
|
||||
range.Hours = range.Minutes / 60;
|
||||
range.Days = range.Hours / 24;
|
||||
['Minutes', 'Hours', 'Days'].forEach(function (unit) {
|
||||
if (range[unit] > 2) {
|
||||
rangeUnit = unit;
|
||||
}
|
||||
});
|
||||
var rangeValue = range[rangeUnit].toFixed(rangeUnit !== 'Seconds' &&
|
||||
rangeUnit !== 'Minutes' ? 1 : 0 // Use decimals for days/hours
|
||||
);
|
||||
// We have the range and the unit to use, find the desc format
|
||||
return chart.langFormat('accessibility.axis.timeRange' + rangeUnit, {
|
||||
chart: chart,
|
||||
axis: axis,
|
||||
range: rangeValue.replace('.0', '')
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Describe an axis from-to range.
|
||||
* @private
|
||||
*/
|
||||
function getAxisFromToDescription(axis) {
|
||||
var chart = axis.chart, options = chart.options, dateRangeFormat = (options &&
|
||||
options.accessibility &&
|
||||
options.accessibility.screenReaderSection.axisRangeDateFormat ||
|
||||
''), extremes = {
|
||||
min: axis.dataMin || axis.min || 0,
|
||||
max: axis.dataMax || axis.max || 0
|
||||
}, format = function (key) {
|
||||
return axis.dateTime ?
|
||||
chart.time.dateFormat(dateRangeFormat, extremes[key]) :
|
||||
extremes[key].toString();
|
||||
};
|
||||
return chart.langFormat('accessibility.axis.rangeFromTo', {
|
||||
chart: chart,
|
||||
axis: axis,
|
||||
rangeFrom: format('min'),
|
||||
rangeTo: format('max')
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Get the DOM element for the first point in the series.
|
||||
* @private
|
||||
* @param {Highcharts.Series} series
|
||||
* The series to get element for.
|
||||
* @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement|undefined}
|
||||
* The DOM element for the point.
|
||||
*/
|
||||
function getSeriesFirstPointElement(series) {
|
||||
if (series.points && series.points.length) {
|
||||
var firstPointWithGraphic = find(series.points, function (p) { return !!p.graphic; });
|
||||
return (firstPointWithGraphic &&
|
||||
firstPointWithGraphic.graphic &&
|
||||
firstPointWithGraphic.graphic.element);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the DOM element for the series that we put accessibility info on.
|
||||
* @private
|
||||
* @param {Highcharts.Series} series
|
||||
* The series to get element for.
|
||||
* @return {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement|undefined}
|
||||
* The DOM element for the series
|
||||
*/
|
||||
function getSeriesA11yElement(series) {
|
||||
var firstPointEl = getSeriesFirstPointElement(series);
|
||||
return (firstPointEl &&
|
||||
firstPointEl.parentNode || series.graph &&
|
||||
series.graph.element || series.group &&
|
||||
series.group.element); // Could be tracker series depending on series type
|
||||
}
|
||||
/**
|
||||
* Remove aria-hidden from element. Also unhides parents of the element, and
|
||||
* hides siblings that are not explicitly unhidden.
|
||||
* @private
|
||||
*/
|
||||
function unhideChartElementFromAT(chart, element) {
|
||||
element.setAttribute('aria-hidden', false);
|
||||
if (element === chart.renderTo ||
|
||||
!element.parentNode ||
|
||||
element.parentNode === doc.body // #16126: Full screen printing
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Hide siblings unless their hidden state is already explicitly set
|
||||
Array.prototype.forEach.call(element.parentNode.childNodes, function (node) {
|
||||
if (!node.hasAttribute('aria-hidden')) {
|
||||
node.setAttribute('aria-hidden', true);
|
||||
}
|
||||
});
|
||||
// Repeat for parent
|
||||
unhideChartElementFromAT(chart, element.parentNode);
|
||||
}
|
||||
/**
|
||||
* Hide series from screen readers.
|
||||
* @private
|
||||
*/
|
||||
function hideSeriesFromAT(series) {
|
||||
var seriesEl = getSeriesA11yElement(series);
|
||||
if (seriesEl) {
|
||||
seriesEl.setAttribute('aria-hidden', true);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get series objects by series name.
|
||||
* @private
|
||||
*/
|
||||
function getSeriesFromName(chart, name) {
|
||||
if (!name) {
|
||||
return chart.series;
|
||||
}
|
||||
return (chart.series || []).filter(function (s) {
|
||||
return s.name === name;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Get point in a series from x/y values.
|
||||
* @private
|
||||
*/
|
||||
function getPointFromXY(series, x, y) {
|
||||
var i = series.length, res;
|
||||
while (i--) {
|
||||
res = find(series[i].points || [], function (p) {
|
||||
return p.x === x && p.y === y;
|
||||
});
|
||||
if (res) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get relative position of point on an x/y axis from 0 to 1.
|
||||
* @private
|
||||
*/
|
||||
function getRelativePointAxisPosition(axis, point) {
|
||||
if (!defined(axis.dataMin) || !defined(axis.dataMax)) {
|
||||
return 0;
|
||||
}
|
||||
var axisStart = axis.toPixels(axis.dataMin), axisEnd = axis.toPixels(axis.dataMax),
|
||||
// We have to use pixel position because of axis breaks, log axis etc.
|
||||
positionProp = axis.coll === 'xAxis' ? 'x' : 'y', pointPos = axis.toPixels(point[positionProp] || 0);
|
||||
return (pointPos - axisStart) / (axisEnd - axisStart);
|
||||
}
|
||||
/**
|
||||
* Get relative position of point on an x/y axis from 0 to 1.
|
||||
* @private
|
||||
*/
|
||||
function scrollToPoint(point) {
|
||||
var xAxis = point.series.xAxis, yAxis = point.series.yAxis, axis = (xAxis && xAxis.scrollbar ? xAxis : yAxis), scrollbar = (axis && axis.scrollbar);
|
||||
if (scrollbar && defined(scrollbar.to) && defined(scrollbar.from)) {
|
||||
var range = scrollbar.to - scrollbar.from;
|
||||
var pos = getRelativePointAxisPosition(axis, point);
|
||||
scrollbar.updatePosition(pos - range / 2, pos + range / 2);
|
||||
fireEvent(scrollbar, 'changed', {
|
||||
from: scrollbar.from,
|
||||
to: scrollbar.to,
|
||||
trigger: 'scrollbar',
|
||||
DOMEvent: null
|
||||
});
|
||||
}
|
||||
}
|
||||
/* *
|
||||
*
|
||||
* Default Export
|
||||
*
|
||||
* */
|
||||
var ChartUtilities = {
|
||||
fireEventOnWrappedOrUnwrappedElement: fireEventOnWrappedOrUnwrappedElement,
|
||||
getChartTitle: getChartTitle,
|
||||
getAxisDescription: getAxisDescription,
|
||||
getAxisRangeDescription: getAxisRangeDescription,
|
||||
getPointFromXY: getPointFromXY,
|
||||
getSeriesFirstPointElement: getSeriesFirstPointElement,
|
||||
getSeriesFromName: getSeriesFromName,
|
||||
getSeriesA11yElement: getSeriesA11yElement,
|
||||
unhideChartElementFromAT: unhideChartElementFromAT,
|
||||
hideSeriesFromAT: hideSeriesFromAT,
|
||||
scrollToPoint: scrollToPoint
|
||||
};
|
||||
export default ChartUtilities;
|
||||
@@ -0,0 +1,62 @@
|
||||
/* *
|
||||
*
|
||||
* (c) 2009-2021 Øystein Moseng
|
||||
*
|
||||
* Class that can keep track of elements added to DOM and clean them up on
|
||||
* destroy.
|
||||
*
|
||||
* License: www.highcharts.com/license
|
||||
*
|
||||
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
||||
*
|
||||
* */
|
||||
'use strict';
|
||||
import H from '../../Core/Globals.js';
|
||||
var doc = H.doc;
|
||||
import HU from './HTMLUtilities.js';
|
||||
var removeElement = HU.removeElement;
|
||||
/* *
|
||||
*
|
||||
* Class
|
||||
*
|
||||
* */
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
var DOMElementProvider = /** @class */ (function () {
|
||||
/* *
|
||||
*
|
||||
* Constructor
|
||||
*
|
||||
* */
|
||||
function DOMElementProvider() {
|
||||
this.elements = [];
|
||||
}
|
||||
/**
|
||||
* Create an element and keep track of it for later removal.
|
||||
* Same args as document.createElement
|
||||
* @private
|
||||
*/
|
||||
DOMElementProvider.prototype.createElement = function () {
|
||||
var el = doc.createElement.apply(doc, arguments);
|
||||
this.elements.push(el);
|
||||
return el;
|
||||
};
|
||||
/**
|
||||
* Destroy all created elements, removing them from the DOM.
|
||||
* @private
|
||||
*/
|
||||
DOMElementProvider.prototype.destroyCreatedElements = function () {
|
||||
this.elements.forEach(function (element) {
|
||||
removeElement(element);
|
||||
});
|
||||
this.elements = [];
|
||||
};
|
||||
return DOMElementProvider;
|
||||
}());
|
||||
/* *
|
||||
*
|
||||
* Default Export
|
||||
*
|
||||
* */
|
||||
export default DOMElementProvider;
|
||||
@@ -0,0 +1,58 @@
|
||||
/* *
|
||||
*
|
||||
* (c) 2009-2021 Øystein Moseng
|
||||
*
|
||||
* Class that can keep track of events added, and clean them up on destroy.
|
||||
*
|
||||
* License: www.highcharts.com/license
|
||||
*
|
||||
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
||||
*
|
||||
* */
|
||||
'use strict';
|
||||
import H from '../../Core/Globals.js';
|
||||
import U from '../../Core/Utilities.js';
|
||||
var addEvent = U.addEvent;
|
||||
/* *
|
||||
*
|
||||
* Class
|
||||
*
|
||||
* */
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
var EventProvider = /** @class */ (function () {
|
||||
/* *
|
||||
*
|
||||
* Constructor
|
||||
*
|
||||
* */
|
||||
function EventProvider() {
|
||||
this.eventRemovers = [];
|
||||
}
|
||||
/**
|
||||
* Add an event to an element and keep track of it for later removal.
|
||||
* Same args as Highcharts.addEvent.
|
||||
* @private
|
||||
*/
|
||||
EventProvider.prototype.addEvent = function () {
|
||||
var remover = addEvent.apply(H, arguments);
|
||||
this.eventRemovers.push(remover);
|
||||
return remover;
|
||||
};
|
||||
/**
|
||||
* Remove all added events.
|
||||
* @private
|
||||
*/
|
||||
EventProvider.prototype.removeAddedEvents = function () {
|
||||
this.eventRemovers.forEach(function (remover) { return remover(); });
|
||||
this.eventRemovers = [];
|
||||
};
|
||||
return EventProvider;
|
||||
}());
|
||||
/* *
|
||||
*
|
||||
* Default Export
|
||||
*
|
||||
* */
|
||||
export default EventProvider;
|
||||
@@ -0,0 +1,305 @@
|
||||
/* *
|
||||
*
|
||||
* (c) 2009-2021 Øystein Moseng
|
||||
*
|
||||
* Utility functions for accessibility module.
|
||||
*
|
||||
* License: www.highcharts.com/license
|
||||
*
|
||||
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
|
||||
*
|
||||
* */
|
||||
'use strict';
|
||||
import H from '../../Core/Globals.js';
|
||||
var doc = H.doc, win = H.win;
|
||||
import U from '../../Core/Utilities.js';
|
||||
var css = U.css;
|
||||
/* *
|
||||
*
|
||||
* Functions
|
||||
*
|
||||
* */
|
||||
/* eslint-disable valid-jsdoc */
|
||||
/**
|
||||
* @private
|
||||
* @param {Highcharts.HTMLDOMElement} el
|
||||
* @param {string} className
|
||||
* @return {void}
|
||||
*/
|
||||
function addClass(el, className) {
|
||||
if (el.classList) {
|
||||
el.classList.add(className);
|
||||
}
|
||||
else if (el.className.indexOf(className) < 0) {
|
||||
// Note: Dumb check for class name exists, should be fine for practical
|
||||
// use cases, but will return false positives if the element has a class
|
||||
// that contains the className.
|
||||
el.className += ' ' + className;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
* @param {Highcharts.HTMLDOMElement} el
|
||||
* @param {string} className
|
||||
* @return {void}
|
||||
*/
|
||||
function removeClass(el, className) {
|
||||
if (el.classList) {
|
||||
el.classList.remove(className);
|
||||
}
|
||||
else {
|
||||
// Note: Dumb logic that will break if the element has a class name that
|
||||
// consists of className plus something else.
|
||||
el.className = el.className.replace(new RegExp(className, 'g'), '');
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Utility function to clone a mouse event for re-dispatching.
|
||||
* @private
|
||||
*/
|
||||
function cloneMouseEvent(e) {
|
||||
if (typeof win.MouseEvent === 'function') {
|
||||
return new win.MouseEvent(e.type, e);
|
||||
}
|
||||
// No MouseEvent support, try using initMouseEvent
|
||||
if (doc.createEvent) {
|
||||
var evt = doc.createEvent('MouseEvent');
|
||||
if (evt.initMouseEvent) {
|
||||
evt.initMouseEvent(e.type, e.bubbles, // #10561, #12161
|
||||
e.cancelable, e.view || win, e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey, e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
return getFakeMouseEvent(e.type);
|
||||
}
|
||||
/**
|
||||
* Utility function to clone a touch event for re-dispatching.
|
||||
* @private
|
||||
*/
|
||||
function cloneTouchEvent(e) {
|
||||
var touchListToTouchArray = function (l) {
|
||||
var touchArray = [];
|
||||
for (var i = 0; i < l.length; ++i) {
|
||||
var item = l.item(i);
|
||||
if (item) {
|
||||
touchArray.push(item);
|
||||
}
|
||||
}
|
||||
return touchArray;
|
||||
};
|
||||
if (typeof win.TouchEvent === 'function') {
|
||||
var newEvent = new win.TouchEvent(e.type, {
|
||||
touches: touchListToTouchArray(e.touches),
|
||||
targetTouches: touchListToTouchArray(e.targetTouches),
|
||||
changedTouches: touchListToTouchArray(e.changedTouches),
|
||||
ctrlKey: e.ctrlKey,
|
||||
shiftKey: e.shiftKey,
|
||||
altKey: e.altKey,
|
||||
metaKey: e.metaKey,
|
||||
bubbles: e.bubbles,
|
||||
cancelable: e.cancelable,
|
||||
composed: e.composed,
|
||||
detail: e.detail,
|
||||
view: e.view
|
||||
});
|
||||
if (e.defaultPrevented) {
|
||||
newEvent.preventDefault();
|
||||
}
|
||||
return newEvent;
|
||||
}
|
||||
var fakeEvt = cloneMouseEvent(e);
|
||||
fakeEvt.touches = e.touches;
|
||||
fakeEvt.changedTouches = e.changedTouches;
|
||||
fakeEvt.targetTouches = e.targetTouches;
|
||||
return fakeEvt;
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
function escapeStringForHTML(str) {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/\//g, '/');
|
||||
}
|
||||
/**
|
||||
* Get an element by ID
|
||||
* @private
|
||||
*/
|
||||
function getElement(id) {
|
||||
return doc.getElementById(id);
|
||||
}
|
||||
/**
|
||||
* Get a fake mouse event of a given type
|
||||
* @private
|
||||
*/
|
||||
function getFakeMouseEvent(type, position) {
|
||||
var pos = position || {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
if (typeof win.MouseEvent === 'function') {
|
||||
return new win.MouseEvent(type, {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
composed: true,
|
||||
view: win,
|
||||
detail: type === 'click' ? 1 : 0,
|
||||
screenX: pos.x,
|
||||
screenY: pos.y,
|
||||
clientX: pos.x,
|
||||
clientY: pos.y
|
||||
});
|
||||
}
|
||||
// No MouseEvent support, try using initMouseEvent
|
||||
if (doc.createEvent) {
|
||||
var evt = doc.createEvent('MouseEvent');
|
||||
if (evt.initMouseEvent) {
|
||||
evt.initMouseEvent(type, true, // Bubble
|
||||
true, // Cancel
|
||||
win, // View
|
||||
type === 'click' ? 1 : 0, // Detail
|
||||
// Coords
|
||||
pos.x, pos.y, pos.x, pos.y,
|
||||
// Pressed keys
|
||||
false, false, false, false, 0, // button
|
||||
null // related target
|
||||
);
|
||||
return evt;
|
||||
}
|
||||
}
|
||||
return { type: type };
|
||||
}
|
||||
/**
|
||||
* Get an appropriate heading level for an element. Corresponds to the
|
||||
* heading level below the previous heading in the DOM.
|
||||
*
|
||||
* Note: Only detects previous headings in the DOM that are siblings,
|
||||
* ancestors, or previous siblings of ancestors. Headings that are nested below
|
||||
* siblings of ancestors (cousins et.al) are not picked up. This is because it
|
||||
* is ambiguous whether or not the nesting is for layout purposes or indicates a
|
||||
* separate section.
|
||||
*
|
||||
* @private
|
||||
* @param {Highcharts.HTMLDOMElement} [element]
|
||||
* @return {string} The heading tag name (h1, h2 etc).
|
||||
* If no nearest heading is found, "p" is returned.
|
||||
*/
|
||||
function getHeadingTagNameForElement(element) {
|
||||
var getIncreasedHeadingLevel = function (tagName) {
|
||||
var headingLevel = parseInt(tagName.slice(1), 10), newLevel = Math.min(6, headingLevel + 1);
|
||||
return 'h' + newLevel;
|
||||
};
|
||||
var isHeading = function (tagName) { return /H[1-6]/.test(tagName); };
|
||||
var getPreviousSiblingsHeading = function (el) {
|
||||
var sibling = el;
|
||||
while (sibling = sibling.previousSibling) { // eslint-disable-line
|
||||
var tagName = sibling.tagName || '';
|
||||
if (isHeading(tagName)) {
|
||||
return tagName;
|
||||
}
|
||||
}
|
||||
return '';
|
||||
};
|
||||
var getHeadingRecursive = function (el) {
|
||||
var prevSiblingsHeading = getPreviousSiblingsHeading(el);
|
||||
if (prevSiblingsHeading) {
|
||||
return getIncreasedHeadingLevel(prevSiblingsHeading);
|
||||
}
|
||||
// No previous siblings are headings, try parent node
|
||||
var parent = el.parentElement;
|
||||
if (!parent) {
|
||||
return 'p';
|
||||
}
|
||||
var parentTagName = parent.tagName;
|
||||
if (isHeading(parentTagName)) {
|
||||
return getIncreasedHeadingLevel(parentTagName);
|
||||
}
|
||||
return getHeadingRecursive(parent);
|
||||
};
|
||||
return getHeadingRecursive(element);
|
||||
}
|
||||
/**
|
||||
* Remove an element from the DOM.
|
||||
* @private
|
||||
* @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} [element]
|
||||
* @return {void}
|
||||
*/
|
||||
function removeElement(element) {
|
||||
if (element && element.parentNode) {
|
||||
element.parentNode.removeChild(element);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Remove all child nodes from an element.
|
||||
* @private
|
||||
* @param {Highcharts.HTMLDOMElement|Highcharts.SVGDOMElement} [element]
|
||||
* @return {void}
|
||||
*/
|
||||
function removeChildNodes(element) {
|
||||
while (element.lastChild) {
|
||||
element.removeChild(element.lastChild);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Utility function. Reverses child nodes of a DOM element.
|
||||
* @private
|
||||
*/
|
||||
function reverseChildNodes(node) {
|
||||
var i = node.childNodes.length;
|
||||
while (i--) {
|
||||
node.appendChild(node.childNodes[i]);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Used for aria-label attributes, painting on a canvas will fail if the
|
||||
* text contains tags.
|
||||
* @private
|
||||
*/
|
||||
function stripHTMLTagsFromString(str) {
|
||||
return typeof str === 'string' ?
|
||||
str.replace(/<\/?[^>]+(>|$)/g, '') : str;
|
||||
}
|
||||
/**
|
||||
* Utility function for hiding an element visually, but still keeping it
|
||||
* available to screen reader users.
|
||||
* @private
|
||||
*/
|
||||
function visuallyHideElement(element) {
|
||||
css(element, {
|
||||
position: 'absolute',
|
||||
width: '1px',
|
||||
height: '1px',
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
clip: 'rect(1px, 1px, 1px, 1px)',
|
||||
marginTop: '-3px',
|
||||
'-ms-filter': 'progid:DXImageTransform.Microsoft.Alpha(Opacity=1)',
|
||||
filter: 'alpha(opacity=1)',
|
||||
opacity: 0.01
|
||||
});
|
||||
}
|
||||
/* *
|
||||
*
|
||||
* Default Export
|
||||
*
|
||||
* */
|
||||
var HTMLUtilities = {
|
||||
addClass: addClass,
|
||||
cloneMouseEvent: cloneMouseEvent,
|
||||
cloneTouchEvent: cloneTouchEvent,
|
||||
escapeStringForHTML: escapeStringForHTML,
|
||||
getElement: getElement,
|
||||
getFakeMouseEvent: getFakeMouseEvent,
|
||||
getHeadingTagNameForElement: getHeadingTagNameForElement,
|
||||
removeChildNodes: removeChildNodes,
|
||||
removeClass: removeClass,
|
||||
removeElement: removeElement,
|
||||
reverseChildNodes: reverseChildNodes,
|
||||
stripHTMLTagsFromString: stripHTMLTagsFromString,
|
||||
visuallyHideElement: visuallyHideElement
|
||||
};
|
||||
export default HTMLUtilities;
|
||||
Reference in New Issue
Block a user