diff --git a/package.json b/package.json index 335579fcf..8602e5a31 100755 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "build.component": "stencil build", "collection.copy": "node scripts/collection-copy.js", "start": "stencil build --dev --watch --serve", + "test": "npm run test.spec", "test.spec": "stencil test --spec", "release": "np --no-2fa", "version": "npm run build" diff --git a/src/components/icon/icon.tsx b/src/components/icon/icon.tsx index 7184d9bb2..7020d21f3 100755 --- a/src/components/icon/icon.tsx +++ b/src/components/icon/icon.tsx @@ -2,6 +2,8 @@ import { Build, Component, Element, Host, Prop, State, Watch, h } from '@stencil import { getSvgContent, ioniconContent } from './request'; import { getName, getUrl, inheritAttributes, isRTL } from './utils'; +let parser: DOMParser; + @Component({ tag: 'ion-icon', assetsDirs: ['svg'], @@ -134,11 +136,27 @@ export class Icon { @Watch('icon') loadIcon() { if (Build.isBrowser && this.isVisible) { + if (!parser) { + /** + * Create an instance of the DOM parser. This creates a single + * parser instance for the entire app, which is more efficient. + */ + parser = new DOMParser(); + } const url = getUrl(this); + if (url) { if (ioniconContent.has(url)) { // sync if it's already loaded this.svgContent = ioniconContent.get(url); + } else if (url.startsWith('data:')) { + const doc = parser.parseFromString(url, 'text/html'); + const svgEl = doc.body.querySelector('svg'); + if (svgEl !== null) { + this.svgContent = svgEl.outerHTML; + } else { + this.svgContent = ''; + } } else { // async if it hasn't been loaded getSvgContent(url, this.sanitize).then(() => (this.svgContent = ioniconContent.get(url))); diff --git a/src/components/test/csp/icon.e2e.ts b/src/components/test/csp/icon.e2e.ts new file mode 100644 index 000000000..c0bbdb8fe --- /dev/null +++ b/src/components/test/csp/icon.e2e.ts @@ -0,0 +1,15 @@ +import { expect } from '@playwright/test'; +import { test } from '../../../utils/test/playwright'; + +test.describe('icon: csp', () => { + + test.beforeEach(async ({ page }) => { + await page.goto('/test/csp'); + }); + + test('should load svg', async ({ page }) => { + const svg = page.locator('ion-icon#icon-usage svg'); + await expect(svg).toBeVisible(); + }); + +}); diff --git a/src/components/test/csp/index.html b/src/components/test/csp/index.html new file mode 100644 index 000000000..a5a92ef2c --- /dev/null +++ b/src/components/test/csp/index.html @@ -0,0 +1,54 @@ + + + +
+ + + +