Skip to content

Commit 45457fe

Browse files
authored
Security: Enable CSP in JS / fix Navigation demo (#32852)
1 parent 97cdc3e commit 45457fe

15 files changed

Lines changed: 208 additions & 87 deletions

File tree

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
::ng-deep #chart-demo {
2-
height: 460px;
3-
}
4-
51
::ng-deep #chart {
62
position: absolute;
73
top: 12px;
@@ -10,7 +6,7 @@
106
height: 347px;
117
}
128

13-
::ng-deep .chart_environment {
9+
::ng-deep .chart-environment {
1410
width: 820px;
1511
position: relative;
1612
margin: 0 auto;
@@ -19,3 +15,18 @@
1915
::ng-deep .controls-pane {
2016
text-align: center;
2117
}
18+
19+
::ng-deep .custom-markup-text {
20+
fill: #fff;
21+
font-family: 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana, sans-serif;
22+
}
23+
24+
::ng-deep .custom-markup-text-title {
25+
font-size: 36px;
26+
font-weight: bold;
27+
}
28+
29+
::ng-deep .custom-markup-text-subtitle {
30+
font-size: 14px;
31+
opacity: 0.8;
32+
}

apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.html

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
<div class="chart_environment">
2-
<div id="custom_markup_container">
1+
<div class="chart-environment">
2+
<div id="custom-markup-container">
33
<svg version="1.1" width="820px" height="420px">
44
<path
55
d="M 0 0 L 820 0 L 820 420 L 0 420 L 0 0"
@@ -17,27 +17,15 @@
1717
></path>
1818
<text
1919
transform="translate(30,89)"
20-
style="
21-
fill: #ffffff;
22-
font-family: 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana,
23-
sans-serif;
24-
font-size: 36px;
25-
font-weight: bold;
26-
"
20+
class="custom-markup-text custom-markup-text-title"
2721
>
2822
<tspan x="0" y="0">Export</tspan>
2923
<tspan x="0" y="38">Custom</tspan>
3024
<tspan x="0" y="76">Markup</tspan>
3125
</text>
3226
<text
3327
transform="translate(32,199)"
34-
style="
35-
opacity: 0.8;
36-
fill: #ffffff;
37-
font-family: 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana,
38-
sans-serif;
39-
font-size: 14px;
40-
"
28+
class="custom-markup-text custom-markup-text-subtitle"
4129
>
4230
<tspan x="0" y="0">Export a chart with</tspan>
4331
<tspan x="0" y="19.2">custom elements</tspan>

apps/demos/Demos/Charts/ExportCustomMarkup/Angular/app/app.component.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,33 @@ export class AppComponent {
5454
}
5555

5656
prepareMarkup() {
57+
const sourceContainer = document.getElementById('custom-markup-container');
58+
const sourceElements = sourceContainer.querySelectorAll('*');
59+
5760
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
5861
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
5962
svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
6063
svg.setAttribute('version', '1.1');
6164
svg.setAttribute('width', '820px');
6265
svg.setAttribute('height', '420px');
63-
svg.innerHTML = document.getElementById('custom_markup_container').innerHTML;
66+
67+
const clonedContainer = sourceContainer.cloneNode(true) as HTMLElement;
68+
const clonedElements = clonedContainer.querySelectorAll('*');
69+
70+
clonedElements.forEach((clonedEl, index) => {
71+
const sourceEl = sourceElements[index] as HTMLElement;
72+
if (!sourceEl) return;
73+
74+
const computed = window.getComputedStyle(sourceEl);
75+
['fill', 'font-family', 'font-size', 'font-weight', 'opacity', 'stroke', 'stroke-width'].forEach((prop) => {
76+
const value = computed.getPropertyValue(prop)?.trim();
77+
if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') {
78+
(clonedEl as SVGElement).setAttribute(prop, value);
79+
}
80+
});
81+
});
82+
83+
svg.innerHTML = clonedContainer.innerHTML;
6484

6585
const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
6686
group.setAttribute('transform', 'translate(305,12)');

apps/demos/Demos/Charts/ExportCustomMarkup/React/App.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,31 @@ import Form from './Form.tsx';
1616

1717
const barPadding = 0.3;
1818

19-
const prepareMarkup = (chartSVG: string, markup: string) => {
19+
const prepareMarkup = (chartSVG: string, sourceContainer: HTMLElement) => {
20+
const sourceElements = sourceContainer.querySelectorAll('*');
21+
2022
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
2123
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
2224
svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
2325
svg.setAttribute('version', '1.1');
2426
svg.setAttribute('width', '820px');
2527
svg.setAttribute('height', '420px');
26-
svg.innerHTML = markup;
28+
const clonedContainer = sourceContainer.cloneNode(true) as HTMLElement;
29+
const clonedElements = clonedContainer.querySelectorAll('*');
30+
31+
clonedElements.forEach((clonedEl, index) => {
32+
const sourceEl = sourceElements[index] as HTMLElement;
33+
if (!sourceEl) return;
2734

35+
const computed = window.getComputedStyle(sourceEl);
36+
['fill', 'font-family', 'font-size', 'font-weight', 'opacity', 'stroke', 'stroke-width'].forEach((prop) => {
37+
const value = computed.getPropertyValue(prop)?.trim();
38+
if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') {
39+
(clonedEl as SVGElement).setAttribute(prop, value);
40+
}
41+
});
42+
});
43+
svg.innerHTML = clonedContainer.innerHTML;
2844
const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
2945
group.setAttribute('transform', 'translate(305,12)');
3046
group.innerHTML = chartSVG;
@@ -40,7 +56,7 @@ function App() {
4056
const onClick = useCallback(() => {
4157
exportFromMarkup(
4258
prepareMarkup(chartRef.current?.instance().svg() ?? '',
43-
childRef.current?.innerHTML ?? ''), {
59+
childRef.current ?? document.createElement('div')), {
4460
width: 820,
4561
height: 420,
4662
margin: 0,
@@ -68,7 +84,7 @@ function App() {
6884

6985
return (
7086
<div id="chart-demo">
71-
<div className="chart_environment">
87+
<div className="chart-environment">
7288
<Form ref={childRef} />
7389
<Chart
7490
ref={chartRef}

apps/demos/Demos/Charts/ExportCustomMarkup/React/Form.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,18 @@
11
import React from 'react';
22

3-
const fontFamily = "'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana, sans-serif";
4-
53
const Form = React.forwardRef<HTMLDivElement>((_, ref) => (
6-
<div id="custom_markup_container" ref={ref}>
4+
<div id="custom-markup-container" ref={ref}>
75
<svg width="820px" height="420px">
86
<path opacity="1" d="M 0 0 L 820 0 L 820 420 L 0 420 L 0 0" stroke="#999999" strokeWidth="1"
97
strokeLinecap="butt" fill="white" strokeLinejoin="miter"></path>
108
<path d="M 13 407 L 128 407 L 232 39 L 13 39" fill="#6D39C3"></path>
119
<path d="M 46 381 L 161 381 L 265 13 L 46 13" opacity="0.5" fill="#6D39C3"></path>
12-
<text transform="translate(30,89)"
13-
style={{
14-
fill: '#FFFFFF', fontFamily, fontSize: 36, fontWeight: 'bold',
15-
}}>
10+
<text transform="translate(30,89)" className="custom-markup-text custom-markup-text-title">
1611
<tspan x="0" y="0">Export </tspan>
1712
<tspan x="0" y="38">Custom</tspan>
1813
<tspan x="0" y="76">Markup</tspan>
1914
</text>
20-
<text transform="translate(32,199)"
21-
style={{
22-
opacity: 0.8, fill: '#FFFFFF', fontFamily, fontSize: 14,
23-
}}>
15+
<text transform="translate(32,199)" className="custom-markup-text custom-markup-text-subtitle">
2416
<tspan x="0" y="0">Export a chart with</tspan>
2517
<tspan x="0" y="19.2">custom elements</tspan>
2618
</text>

apps/demos/Demos/Charts/ExportCustomMarkup/React/styles.css

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
height: 347px;
1111
}
1212

13-
.chart_environment {
13+
.chart-environment {
1414
width: 820px;
1515
position: relative;
1616
margin: 0 auto;
@@ -19,3 +19,18 @@
1919
.controls-pane {
2020
text-align: center;
2121
}
22+
23+
.custom-markup-text {
24+
fill: #fff;
25+
font-family: 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana, sans-serif;
26+
}
27+
28+
.custom-markup-text-title {
29+
font-size: 36px;
30+
font-weight: bold;
31+
}
32+
33+
.custom-markup-text-subtitle {
34+
font-size: 14px;
35+
opacity: 0.8;
36+
}

apps/demos/Demos/Charts/ExportCustomMarkup/ReactJs/App.js

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,36 @@ import { dataSource } from './data.js';
1414
import Form from './Form.js';
1515

1616
const barPadding = 0.3;
17-
const prepareMarkup = (chartSVG, markup) => {
17+
const prepareMarkup = (chartSVG, sourceContainer) => {
18+
const sourceElements = sourceContainer.querySelectorAll('*');
1819
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
1920
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
2021
svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
2122
svg.setAttribute('version', '1.1');
2223
svg.setAttribute('width', '820px');
2324
svg.setAttribute('height', '420px');
24-
svg.innerHTML = markup;
25+
const clonedContainer = sourceContainer.cloneNode(true);
26+
const clonedElements = clonedContainer.querySelectorAll('*');
27+
clonedElements.forEach((clonedEl, index) => {
28+
const sourceEl = sourceElements[index];
29+
if (!sourceEl) return;
30+
const computed = window.getComputedStyle(sourceEl);
31+
[
32+
'fill',
33+
'font-family',
34+
'font-size',
35+
'font-weight',
36+
'opacity',
37+
'stroke',
38+
'stroke-width',
39+
].forEach((prop) => {
40+
const value = computed.getPropertyValue(prop)?.trim();
41+
if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') {
42+
clonedEl.setAttribute(prop, value);
43+
}
44+
});
45+
});
46+
svg.innerHTML = clonedContainer.innerHTML;
2547
const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
2648
group.setAttribute('transform', 'translate(305,12)');
2749
group.innerHTML = chartSVG;
@@ -33,7 +55,10 @@ function App() {
3355
const chartRef = useRef(null);
3456
const onClick = useCallback(() => {
3557
exportFromMarkup(
36-
prepareMarkup(chartRef.current?.instance().svg() ?? '', childRef.current?.innerHTML ?? ''),
58+
prepareMarkup(
59+
chartRef.current?.instance().svg() ?? '',
60+
childRef.current ?? document.createElement('div'),
61+
),
3762
{
3863
width: 820,
3964
height: 420,
@@ -55,7 +80,7 @@ function App() {
5580
}, []);
5681
return (
5782
<div id="chart-demo">
58-
<div className="chart_environment">
83+
<div className="chart-environment">
5984
<Form ref={childRef} />
6085
<Chart
6186
ref={chartRef}

apps/demos/Demos/Charts/ExportCustomMarkup/ReactJs/Form.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import React from 'react';
22

3-
const fontFamily = "'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana, sans-serif";
43
const Form = React.forwardRef((_, ref) => (
54
<div
6-
id="custom_markup_container"
5+
id="custom-markup-container"
76
ref={ref}
87
>
98
<svg
@@ -30,12 +29,7 @@ const Form = React.forwardRef((_, ref) => (
3029
></path>
3130
<text
3231
transform="translate(30,89)"
33-
style={{
34-
fill: '#FFFFFF',
35-
fontFamily,
36-
fontSize: 36,
37-
fontWeight: 'bold',
38-
}}
32+
className="custom-markup-text custom-markup-text-title"
3933
>
4034
<tspan
4135
x="0"
@@ -58,12 +52,7 @@ const Form = React.forwardRef((_, ref) => (
5852
</text>
5953
<text
6054
transform="translate(32,199)"
61-
style={{
62-
opacity: 0.8,
63-
fill: '#FFFFFF',
64-
fontFamily,
65-
fontSize: 14,
66-
}}
55+
className="custom-markup-text custom-markup-text-subtitle"
6756
>
6857
<tspan
6958
x="0"

apps/demos/Demos/Charts/ExportCustomMarkup/ReactJs/styles.css

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
height: 347px;
1111
}
1212

13-
.chart_environment {
13+
.chart-environment {
1414
width: 820px;
1515
position: relative;
1616
margin: 0 auto;
@@ -19,3 +19,18 @@
1919
.controls-pane {
2020
text-align: center;
2121
}
22+
23+
.custom-markup-text {
24+
fill: #fff;
25+
font-family: 'Segoe UI', 'Helvetica Neue', 'Trebuchet MS', Verdana, sans-serif;
26+
}
27+
28+
.custom-markup-text-title {
29+
font-size: 36px;
30+
font-weight: bold;
31+
}
32+
33+
.custom-markup-text-subtitle {
34+
font-size: 14px;
35+
opacity: 0.8;
36+
}

apps/demos/Demos/Charts/ExportCustomMarkup/Vue/App.vue

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<template>
22
<div id="chart-demo">
3-
<div class="chart_environment">
3+
<div class="chart-environment">
44
<Form ref="form"/>
55
<DxChart
66
id="chart"
@@ -75,20 +75,32 @@ import Form from './Form.vue';
7575
const form = ref();
7676
const chart = ref();
7777
78-
const prepareMarkup = (chartSVG: string, markup: string): SVGElement => {
78+
const prepareMarkup = (chartSVG: string, sourceContainer: HTMLElement): SVGElement => {
79+
const sourceElements = sourceContainer.querySelectorAll('*');
7980
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
8081
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
8182
svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
8283
svg.setAttribute('version', '1.1');
8384
svg.setAttribute('width', '820px');
8485
svg.setAttribute('height', '420px');
85-
svg.innerHTML = markup;
86-
86+
const clonedContainer = sourceContainer.cloneNode(true) as HTMLElement;
87+
const clonedElements = clonedContainer.querySelectorAll('*');
88+
clonedElements.forEach((clonedEl, index) => {
89+
const sourceEl = sourceElements[index] as HTMLElement;
90+
if (!sourceEl) return;
91+
const computed = window.getComputedStyle(sourceEl);
92+
['fill', 'font-family', 'font-size', 'font-weight', 'opacity', 'stroke', 'stroke-width'].forEach((prop) => {
93+
const value = computed.getPropertyValue(prop)?.trim();
94+
if (value && value !== 'auto' && value !== 'normal' && value !== 'initial') {
95+
(clonedEl as SVGElement).setAttribute(prop, value);
96+
}
97+
});
98+
});
99+
svg.innerHTML = clonedContainer.innerHTML;
87100
const group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
88101
group.setAttribute('transform', 'translate(305,12)');
89102
group.innerHTML = chartSVG;
90103
svg.appendChild(group);
91-
92104
return svg;
93105
};
94106
@@ -127,7 +139,7 @@ function onClick(): void {
127139
height: 347px;
128140
}
129141
130-
.chart_environment {
142+
.chart-environment {
131143
width: 820px;
132144
position: relative;
133145
margin: 0 auto;

0 commit comments

Comments
 (0)