Skip to content

Commit 3b0af7c

Browse files
authored
feat(config): add option to disable custom html functionality (#26956)
1 parent 6c639ff commit 3b0af7c

File tree

12 files changed

+351
-28
lines changed

12 files changed

+351
-28
lines changed

core/src/components.d.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ export namespace Components {
192192
*/
193193
"leaveAnimation"?: AnimationBuilder;
194194
/**
195-
* The main message to be displayed in the alert. `message` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
195+
* The main message to be displayed in the alert. `message` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
196196
*/
197197
"message"?: string | IonicSafeString;
198198
/**
@@ -1039,7 +1039,7 @@ export namespace Components {
10391039
*/
10401040
"loadingSpinner"?: SpinnerTypes | null;
10411041
/**
1042-
* Optional text to display while loading. `loadingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
1042+
* Optional text to display while loading. `loadingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
10431043
*/
10441044
"loadingText"?: string | IonicSafeString;
10451045
}
@@ -1422,7 +1422,7 @@ export namespace Components {
14221422
*/
14231423
"leaveAnimation"?: AnimationBuilder;
14241424
/**
1425-
* Optional text content to display in the loading indicator.
1425+
* Optional text content to display in the loading indicator. This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
14261426
*/
14271427
"message"?: string | IonicSafeString;
14281428
/**
@@ -2221,15 +2221,15 @@ export namespace Components {
22212221
*/
22222222
"pullingIcon"?: SpinnerTypes | string | null;
22232223
/**
2224-
* The text you want to display when you begin to pull down. `pullingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
2224+
* The text you want to display when you begin to pull down. `pullingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
22252225
*/
22262226
"pullingText"?: string | IonicSafeString;
22272227
/**
22282228
* An animated SVG spinner that shows when refreshing begins
22292229
*/
22302230
"refreshingSpinner"?: SpinnerTypes | null;
22312231
/**
2232-
* The text you want to display when performing a refresh. `refreshingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
2232+
* The text you want to display when performing a refresh. `refreshingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
22332233
*/
22342234
"refreshingText"?: string | IonicSafeString;
22352235
}
@@ -2990,7 +2990,7 @@ export namespace Components {
29902990
*/
29912991
"leaveAnimation"?: AnimationBuilder;
29922992
/**
2993-
* Message to be shown in the toast.
2993+
* Message to be shown in the toast. This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
29942994
*/
29952995
"message"?: string | IonicSafeString;
29962996
/**
@@ -4147,7 +4147,7 @@ declare namespace LocalJSX {
41474147
*/
41484148
"leaveAnimation"?: AnimationBuilder;
41494149
/**
4150-
* The main message to be displayed in the alert. `message` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
4150+
* The main message to be displayed in the alert. `message` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
41514151
*/
41524152
"message"?: string | IonicSafeString;
41534153
/**
@@ -5045,7 +5045,7 @@ declare namespace LocalJSX {
50455045
*/
50465046
"loadingSpinner"?: SpinnerTypes | null;
50475047
/**
5048-
* Optional text to display while loading. `loadingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
5048+
* Optional text to display while loading. `loadingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
50495049
*/
50505050
"loadingText"?: string | IonicSafeString;
50515051
}
@@ -5420,7 +5420,7 @@ declare namespace LocalJSX {
54205420
*/
54215421
"leaveAnimation"?: AnimationBuilder;
54225422
/**
5423-
* Optional text content to display in the loading indicator.
5423+
* Optional text content to display in the loading indicator. This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
54245424
*/
54255425
"message"?: string | IonicSafeString;
54265426
/**
@@ -6188,15 +6188,15 @@ declare namespace LocalJSX {
61886188
*/
61896189
"pullingIcon"?: SpinnerTypes | string | null;
61906190
/**
6191-
* The text you want to display when you begin to pull down. `pullingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
6191+
* The text you want to display when you begin to pull down. `pullingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
61926192
*/
61936193
"pullingText"?: string | IonicSafeString;
61946194
/**
61956195
* An animated SVG spinner that shows when refreshing begins
61966196
*/
61976197
"refreshingSpinner"?: SpinnerTypes | null;
61986198
/**
6199-
* The text you want to display when performing a refresh. `refreshingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
6199+
* The text you want to display when performing a refresh. `refreshingText` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `<Ionic>` would become `&lt;Ionic&gt;` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
62006200
*/
62016201
"refreshingText"?: string | IonicSafeString;
62026202
}
@@ -6999,7 +6999,7 @@ declare namespace LocalJSX {
69996999
*/
70007000
"leaveAnimation"?: AnimationBuilder;
70017001
/**
7002-
* Message to be shown in the toast.
7002+
* Message to be shown in the toast. This property accepts custom HTML as a string. Developers who only want to pass plain text can disable the custom HTML functionality by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
70037003
*/
70047004
"message"?: string | IonicSafeString;
70057005
/**

core/src/components/alert/alert.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import type { ComponentInterface, EventEmitter } from '@stencil/core';
22
import { Component, Element, Event, Host, Listen, Method, Prop, Watch, forceUpdate, h } from '@stencil/core';
33

4+
import { config } from '../../global/config';
45
import { getIonMode } from '../../global/ionic-global';
56
import type {
67
AlertButton,
@@ -12,6 +13,7 @@ import type {
1213
OverlayEventDetail,
1314
OverlayInterface,
1415
} from '../../interface';
16+
import { ENABLE_HTML_CONTENT_DEFAULT } from '../../utils/config';
1517
import type { Gesture } from '../../utils/gesture';
1618
import { createButtonActiveGesture } from '../../utils/gesture/button-active';
1719
import { BACKDROP, dismiss, eventMethod, isCancel, prepareOverlay, present, safeCall } from '../../utils/overlays';
@@ -39,6 +41,7 @@ import { mdLeaveAnimation } from './animations/md.leave';
3941
scoped: true,
4042
})
4143
export class Alert implements ComponentInterface, OverlayInterface {
44+
private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
4245
private activeId?: string;
4346
private inputType?: string;
4447
private processedInputs: AlertInput[] = [];
@@ -93,6 +96,11 @@ export class Alert implements ComponentInterface, OverlayInterface {
9396
* `&lt;Ionic&gt;`
9497
*
9598
* For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
99+
*
100+
* This property accepts custom HTML as a string.
101+
* Developers who only want to pass plain text
102+
* can disable the custom HTML functionality
103+
* by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
96104
*/
97105
@Prop() message?: string | IonicSafeString;
98106

@@ -579,6 +587,19 @@ export class Alert implements ComponentInterface, OverlayInterface {
579587
);
580588
}
581589

590+
private renderAlertMessage(msgId: string) {
591+
const { customHTMLEnabled, message } = this;
592+
if (customHTMLEnabled) {
593+
return <div id={msgId} class="alert-message" innerHTML={sanitizeDOMString(message)}></div>;
594+
}
595+
596+
return (
597+
<div id={msgId} class="alert-message">
598+
{message}
599+
</div>
600+
);
601+
}
602+
582603
render() {
583604
const { overlayIndex, header, subHeader, message, htmlAttributes } = this;
584605
const mode = getIonMode(this);
@@ -631,7 +652,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
631652
)}
632653
</div>
633654

634-
<div id={msgId} class="alert-message" innerHTML={sanitizeDOMString(message)}></div>
655+
{this.renderAlertMessage(msgId)}
635656

636657
{this.renderAlertInputs()}
637658
{this.renderAlertButtons()}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { newSpecPage } from '@stencil/core/testing';
2+
import { Alert } from '../alert';
3+
import { config } from '../../../global/config';
4+
5+
describe('alert: custom html', () => {
6+
it('should allow for custom html by default', async () => {
7+
const page = await newSpecPage({
8+
components: [Alert],
9+
html: `<ion-alert message="<button class='custom-html'>Custom Text</button>"></ion-alert>`,
10+
});
11+
12+
const content = page.body.querySelector('.alert-message');
13+
expect(content.textContent).toContain('Custom Text');
14+
expect(content.querySelector('button.custom-html')).not.toBe(null);
15+
});
16+
17+
it('should allow for custom html', async () => {
18+
config.reset({ innerHTMLTemplatesEnabled: true });
19+
const page = await newSpecPage({
20+
components: [Alert],
21+
html: `<ion-alert message="<button class='custom-html'>Custom Text</button>"></ion-alert>`,
22+
});
23+
24+
const content = page.body.querySelector('.alert-message');
25+
expect(content.textContent).toContain('Custom Text');
26+
expect(content.querySelector('button.custom-html')).not.toBe(null);
27+
});
28+
29+
it('should not allow for custom html', async () => {
30+
config.reset({ innerHTMLTemplatesEnabled: false });
31+
const page = await newSpecPage({
32+
components: [Alert],
33+
html: `<ion-alert message="<button class='custom-html'>Custom Text</button>"></ion-alert>`,
34+
});
35+
36+
const content = page.body.querySelector('.alert-message');
37+
expect(content.textContent).toContain('Custom Text');
38+
expect(content.querySelector('button.custom-html')).toBe(null);
39+
});
40+
});

core/src/components/infinite-scroll-content/infinite-scroll-content.tsx

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Component, Host, Prop, h } from '@stencil/core';
44
import { config } from '../../global/config';
55
import { getIonMode } from '../../global/ionic-global';
66
import type { SpinnerTypes } from '../../interface';
7+
import { ENABLE_HTML_CONTENT_DEFAULT } from '../../utils/config';
78
import type { IonicSafeString } from '../../utils/sanitization';
89
import { sanitizeDOMString } from '../../utils/sanitization';
910

@@ -15,6 +16,8 @@ import { sanitizeDOMString } from '../../utils/sanitization';
1516
},
1617
})
1718
export class InfiniteScrollContent implements ComponentInterface {
19+
private customHTMLEnabled = config.get('innerHTMLTemplatesEnabled', ENABLE_HTML_CONTENT_DEFAULT);
20+
1821
/**
1922
* An animated SVG spinner that shows while loading.
2023
*/
@@ -28,6 +31,11 @@ export class InfiniteScrollContent implements ComponentInterface {
2831
* `&lt;Ionic&gt;`
2932
*
3033
* For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
34+
*
35+
* This property accepts custom HTML as a string.
36+
* Developers who only want to pass plain text
37+
* can disable the custom HTML functionality
38+
* by setting `innerHTMLTemplatesEnabled: false` in the Ionic config.
3139
*/
3240
@Prop() loadingText?: string | IonicSafeString;
3341

@@ -41,6 +49,15 @@ export class InfiniteScrollContent implements ComponentInterface {
4149
}
4250
}
4351

52+
private renderLoadingText() {
53+
const { customHTMLEnabled, loadingText } = this;
54+
if (customHTMLEnabled) {
55+
return <div class="infinite-loading-text" innerHTML={sanitizeDOMString(loadingText)}></div>;
56+
}
57+
58+
return <div class="infinite-loading-text">{this.loadingText}</div>;
59+
}
60+
4461
render() {
4562
const mode = getIonMode(this);
4663
return (
@@ -58,9 +75,7 @@ export class InfiniteScrollContent implements ComponentInterface {
5875
<ion-spinner name={this.loadingSpinner} />
5976
</div>
6077
)}
61-
{this.loadingText !== undefined && (
62-
<div class="infinite-loading-text" innerHTML={sanitizeDOMString(this.loadingText)} />
63-
)}
78+
{this.loadingText !== undefined && this.renderLoadingText()}
6479
</div>
6580
</Host>
6681
);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { newSpecPage } from '@stencil/core/testing';
2+
import { InfiniteScrollContent } from '../infinite-scroll-content';
3+
import { config } from '../../../global/config';
4+
5+
describe('infinite-scroll-content: custom html', () => {
6+
it('should allow for custom html by default', async () => {
7+
const page = await newSpecPage({
8+
components: [InfiniteScrollContent],
9+
html: `<ion-infinite-scroll-content loading-text="<button class='custom-html'>Custom Text</button>"></ion-infinite-scroll-content>`,
10+
});
11+
12+
const content = page.body.querySelector('.infinite-loading-text');
13+
expect(content.textContent).toContain('Custom Text');
14+
expect(content.querySelector('button.custom-html')).not.toBe(null);
15+
});
16+
17+
it('should allow for custom html', async () => {
18+
config.reset({ innerHTMLTemplatesEnabled: true });
19+
const page = await newSpecPage({
20+
components: [InfiniteScrollContent],
21+
html: `<ion-infinite-scroll-content loading-text="<button class='custom-html'>Custom Text</button>"></ion-infinite-scroll-content>`,
22+
});
23+
24+
const content = page.body.querySelector('.infinite-loading-text');
25+
expect(content.textContent).toContain('Custom Text');
26+
expect(content.querySelector('button.custom-html')).not.toBe(null);
27+
});
28+
29+
it('should not allow for custom html', async () => {
30+
config.reset({ innerHTMLTemplatesEnabled: false });
31+
const page = await newSpecPage({
32+
components: [InfiniteScrollContent],
33+
html: `<ion-infinite-scroll-content loading-text="<button class='custom-html'>Custom Text2</button>"></ion-infinite-scroll-content>`,
34+
});
35+
36+
const content = page.body.querySelector('.infinite-loading-text');
37+
expect(content.textContent).toContain('Custom Text');
38+
expect(content.querySelector('button.custom-html')).toBe(null);
39+
});
40+
});

0 commit comments

Comments
 (0)