diff --git a/src/apexcharts.js b/src/apexcharts.js index 76b490a1f..1cf65d389 100644 --- a/src/apexcharts.js +++ b/src/apexcharts.js @@ -84,6 +84,10 @@ export default class ApexCharts { this.css = document.createElement('style') this.css.id = 'apexcharts-css' this.css.textContent = apexCSS + const nonce = this.opts.chart?.nonce || this.w.config.chart.nonce; + if (nonce) { + this.css.setAttribute('nonce', nonce); + } if (inShadowRoot) { // We are in Shadow DOM, add to shadow root diff --git a/src/modules/legend/Helpers.js b/src/modules/legend/Helpers.js index 816b8fe1a..ed9d5baf7 100644 --- a/src/modules/legend/Helpers.js +++ b/src/modules/legend/Helpers.js @@ -10,6 +10,10 @@ export default class Helpers { getLegendStyles() { let stylesheet = document.createElement('style') stylesheet.setAttribute('type', 'text/css') + const nonce = this.lgCtx.ctx?.opts?.chart?.nonce || this.w.config.chart.nonce; + if (nonce) { + stylesheet.setAttribute('nonce', nonce); + } const text = ` diff --git a/src/modules/settings/Options.js b/src/modules/settings/Options.js index 9ca0aa1f4..4c0f6064b 100644 --- a/src/modules/settings/Options.js +++ b/src/modules/settings/Options.js @@ -310,6 +310,7 @@ export default class Options { redrawOnWindowResize: true, id: undefined, group: undefined, + nonce: undefined, offsetX: 0, offsetY: 0, selection: { diff --git a/tests/unit/nonce.spec.js b/tests/unit/nonce.spec.js new file mode 100644 index 000000000..2e8597272 --- /dev/null +++ b/tests/unit/nonce.spec.js @@ -0,0 +1,91 @@ +import { createChartWithOptions } from './utils/utils.js' + +describe('chart.nonce option', () => { + beforeEach(() => { + window.Apex = {}; + }); + afterEach(() => { + document.getElementsByTagName('html')[0].innerHTML = '' + }) + + it('undefined (default) will not render a nonce attribute', () => { + createChartWithOptions({ + series: [ + { + name: "A", + data: [ + [1, 1], + [4, 4], + [3, 3], + ], + }, + { + name: "B", + data: [ + [2, 2], + [5, 5], + [6, 6], + ], + }, + ], + chart: { + type: 'bar', + }, + }) + expect(document.head.querySelectorAll('#apexcharts-css').length).toBe(1) + expect( + document.head.querySelectorAll('#apexcharts-css[nonce]').length + ).toBe(0) + expect(document.body.querySelectorAll('foreignObject style').length).toBe(1) + }) + + it('will render a nonce attribute when provided as an option', () => { + createChartWithOptions({ + series: [ + { + data: [ + [1, 1], + [4, 4], + [3, 3], + ], + }, + ], + chart: { + type: 'bar', + nonce: 'noncevalue1', + }, + }) + expect(document.head.querySelectorAll('#apexcharts-css').length).toBe(1) + expect( + document.head.querySelectorAll("#apexcharts-css[nonce='noncevalue1']") + .length + ).toBe(1) + }) + + it('will render a nonce attribute when defined as a global config', () => { + window.Apex = { + chart: { + nonce: 'noncevalue2' + } + }; + createChartWithOptions({ + series: [ + { + data: [ + [1, 1], + [4, 4], + [3, 3], + ], + }, + ], + chart: { + type: 'bar', + }, + }) + expect(document.head.querySelectorAll('#apexcharts-css').length).toBe(1) + expect( + document.head.querySelectorAll("#apexcharts-css[nonce='noncevalue2']") + .length + ).toBe(1) + }) +})