diff --git a/CHANGELOG.md b/CHANGELOG.md
index ba8d68f404..ae91b6aec8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,13 @@
+## [4.3.1](https://github.com/ionic-team/ionic/compare/v4.3.0...v4.3.1) (2019-04-26)
+
+
+### Bug Fixes
+
+* **angular:** support replaceUrl with angular <7.2 ([#18106](https://github.com/ionic-team/ionic/issues/18106)) ([eb3cbe4](https://github.com/ionic-team/ionic/commit/eb3cbe4))
+* sanitize components using innerHTML ([#18146](https://github.com/ionic-team/ionic/issues/18146)) ([b839e6f](https://github.com/ionic-team/ionic/commit/b839e6f))
+
+
+
# [4.3.0 Lithium](https://github.com/ionic-team/ionic/compare/v4.2.0...v4.3.0) (2019-04-17)
diff --git a/angular/package.json b/angular/package.json
index 0b9598d344..dbb841ced7 100644
--- a/angular/package.json
+++ b/angular/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
- "version": "4.3.0",
+ "version": "4.3.1",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -45,7 +45,7 @@
"css/"
],
"dependencies": {
- "@ionic/core": "4.3.0",
+ "@ionic/core": "4.3.1",
"tslib": "^1.9.3"
},
"peerDependencies": {
diff --git a/angular/src/directives/navigation/stack-controller.ts b/angular/src/directives/navigation/stack-controller.ts
index 0680278c31..a06eb0491c 100644
--- a/angular/src/directives/navigation/stack-controller.ts
+++ b/angular/src/directives/navigation/stack-controller.ts
@@ -59,7 +59,22 @@ export class StackController {
}
const viewsSnapshot = this.views.slice();
- const currentNavigation = this.router.getCurrentNavigation();
+ let currentNavigation;
+
+ const router = (this.router as any);
+
+ // Angular >= 7.2.0
+ if (router.getCurrentNavigation) {
+ currentNavigation = router.getCurrentNavigation();
+
+ // Angular < 7.2.0
+ } else if (
+ router.navigations &&
+ router.navigations.value
+ ) {
+ currentNavigation = router.navigations.value;
+ }
+
/**
* If the navigation action
* sets `replaceUrl: true`
diff --git a/core/README.md b/core/README.md
index 1441ec6e5f..cc4ce0015e 100644
--- a/core/README.md
+++ b/core/README.md
@@ -23,8 +23,8 @@ The Ionic Core package contains the Web Components that make up the reusable UI
Easiest way to start using Ionic Core is by adding a script tag to the CDN:
```html
-
-
+
+
```
Any Ionic component added to the webpage will automatically load. This includes writing the component tag directly in HTML, or using JavaScript such as `document.createElement('ion-toggle')`.
diff --git a/core/package.json b/core/package.json
index a9c5949253..5979ca9de1 100644
--- a/core/package.json
+++ b/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
- "version": "4.3.0",
+ "version": "4.3.1",
"description": "Base components for Ionic",
"keywords": [
"ionic",
diff --git a/core/src/components.d.ts b/core/src/components.d.ts
index 7a1b044b4c..26b32bffc5 100644
--- a/core/src/components.d.ts
+++ b/core/src/components.d.ts
@@ -285,7 +285,7 @@ export namespace Components {
*/
'leaveAnimation'?: AnimationBuilder;
/**
- * The main message to be displayed in the alert.
+ * 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'message'?: string;
/**
@@ -352,7 +352,7 @@ export namespace Components {
*/
'leaveAnimation'?: AnimationBuilder;
/**
- * The main message to be displayed in the alert.
+ * 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'message'?: string;
/**
@@ -1566,7 +1566,7 @@ export namespace Components {
*/
'loadingSpinner'?: SpinnerTypes | null;
/**
- * Optional text to display while loading.
+ * 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'loadingText'?: string;
}
@@ -1576,7 +1576,7 @@ export namespace Components {
*/
'loadingSpinner'?: SpinnerTypes | null;
/**
- * Optional text to display while loading.
+ * 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'loadingText'?: string;
}
@@ -3418,7 +3418,7 @@ export namespace Components {
*/
'pullingIcon'?: string | null;
/**
- * The text you want to display when you begin to pull down
+ * 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'pullingText'?: string;
/**
@@ -3426,7 +3426,7 @@ export namespace Components {
*/
'refreshingSpinner'?: SpinnerTypes | null;
/**
- * The text you want to display when performing a refresh
+ * 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'refreshingText'?: string;
}
@@ -3436,7 +3436,7 @@ export namespace Components {
*/
'pullingIcon'?: string | null;
/**
- * The text you want to display when you begin to pull down
+ * 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'pullingText'?: string;
/**
@@ -3444,7 +3444,7 @@ export namespace Components {
*/
'refreshingSpinner'?: SpinnerTypes | null;
/**
- * The text you want to display when performing a refresh
+ * 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'refreshingText'?: string;
}
@@ -3728,7 +3728,7 @@ export namespace Components {
*/
'mode': Mode;
/**
- * Set the input's placeholder.
+ * Set the input's placeholder. `placeholder` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'placeholder': string;
/**
@@ -3818,7 +3818,7 @@ export namespace Components {
*/
'onIonInput'?: (event: CustomEvent) => void;
/**
- * Set the input's placeholder.
+ * Set the input's placeholder. `placeholder` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
'placeholder'?: string;
/**
diff --git a/core/src/components/alert/alert.tsx b/core/src/components/alert/alert.tsx
index d3d0937f02..ad3b0abb9e 100644
--- a/core/src/components/alert/alert.tsx
+++ b/core/src/components/alert/alert.tsx
@@ -2,6 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Listen, Me
import { AlertButton, AlertInput, Animation, AnimationBuilder, Config, CssClassMap, Mode, OverlayEventDetail, OverlayInterface } from '../../interface';
import { BACKDROP, dismiss, eventMethod, isCancel, present } from '../../utils/overlays';
+import { sanitizeDOMString } from '../../utils/sanitization';
import { getClassMap } from '../../utils/theme';
import { iosEnterAnimation } from './animations/ios.enter';
@@ -72,6 +73,12 @@ export class Alert implements ComponentInterface, OverlayInterface {
/**
* 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 `` would become
+ * `<Ionic>`
+ *
+ * For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
@Prop() message?: string;
@@ -440,7 +447,7 @@ export class Alert implements ComponentInterface, OverlayInterface {
{this.subHeader &&
{this.subHeader}
}
-
+
{this.renderAlertInputs(labelledById)}
{this.renderAlertButtons()}
diff --git a/core/src/components/alert/readme.md b/core/src/components/alert/readme.md
index ca8afe3668..5744aed888 100644
--- a/core/src/components/alert/readme.md
+++ b/core/src/components/alert/readme.md
@@ -1055,21 +1055,21 @@ export default {
## Properties
-| Property | Attribute | Description | Type | Default |
-| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------- |
-| `animated` | `animated` | If `true`, the alert will animate. | `boolean` | `true` |
-| `backdropDismiss` | `backdrop-dismiss` | If `true`, the alert will be dismissed when the backdrop is clicked. | `boolean` | `true` |
-| `buttons` | -- | Array of buttons to be added to the alert. | `(string \| AlertButton)[]` | `[]` |
-| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
-| `enterAnimation` | -- | Animation to use when the alert is presented. | `((Animation: Animation, baseEl: any, opts?: any) => Promise) \| undefined` | `undefined` |
-| `header` | `header` | The main title in the heading of the alert. | `string \| undefined` | `undefined` |
-| `inputs` | -- | Array of input to show in the alert. | `AlertInput[]` | `[]` |
-| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
-| `leaveAnimation` | -- | Animation to use when the alert is dismissed. | `((Animation: Animation, baseEl: any, opts?: any) => Promise) \| undefined` | `undefined` |
-| `message` | `message` | The main message to be displayed in the alert. | `string \| undefined` | `undefined` |
-| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
-| `subHeader` | `sub-header` | The subtitle in the heading of the alert. Displayed under the title. | `string \| undefined` | `undefined` |
-| `translucent` | `translucent` | If `true`, the alert will be translucent. | `boolean` | `false` |
+| Property | Attribute | Description | Type | Default |
+| ----------------- | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------- |
+| `animated` | `animated` | If `true`, the alert will animate. | `boolean` | `true` |
+| `backdropDismiss` | `backdrop-dismiss` | If `true`, the alert will be dismissed when the backdrop is clicked. | `boolean` | `true` |
+| `buttons` | -- | Array of buttons to be added to the alert. | `(string \| AlertButton)[]` | `[]` |
+| `cssClass` | `css-class` | Additional classes to apply for custom CSS. If multiple classes are provided they should be separated by spaces. | `string \| string[] \| undefined` | `undefined` |
+| `enterAnimation` | -- | Animation to use when the alert is presented. | `((Animation: Animation, baseEl: any, opts?: any) => Promise) \| undefined` | `undefined` |
+| `header` | `header` | The main title in the heading of the alert. | `string \| undefined` | `undefined` |
+| `inputs` | -- | Array of input to show in the alert. | `AlertInput[]` | `[]` |
+| `keyboardClose` | `keyboard-close` | If `true`, the keyboard will be automatically dismissed when the overlay is presented. | `boolean` | `true` |
+| `leaveAnimation` | -- | Animation to use when the alert is dismissed. | `((Animation: Animation, baseEl: any, opts?: any) => Promise) \| undefined` | `undefined` |
+| `message` | `message` | 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) | `string \| undefined` | `undefined` |
+| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
+| `subHeader` | `sub-header` | The subtitle in the heading of the alert. Displayed under the title. | `string \| undefined` | `undefined` |
+| `translucent` | `translucent` | If `true`, the alert will be translucent. | `boolean` | `false` |
## Events
diff --git a/core/src/components/infinite-scroll-content/infinite-scroll-content.tsx b/core/src/components/infinite-scroll-content/infinite-scroll-content.tsx
index 95d6d71407..b440eb0eb4 100644
--- a/core/src/components/infinite-scroll-content/infinite-scroll-content.tsx
+++ b/core/src/components/infinite-scroll-content/infinite-scroll-content.tsx
@@ -1,6 +1,7 @@
import { Component, ComponentInterface, Prop } from '@stencil/core';
import { Config, Mode, SpinnerTypes } from '../../interface';
+import { sanitizeDOMString } from '../../utils/sanitization';
@Component({
tag: 'ion-infinite-scroll-content',
@@ -22,6 +23,12 @@ export class InfiniteScrollContent implements ComponentInterface {
/**
* 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 `` would become
+ * `<Ionic>`
+ *
+ * For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
@Prop() loadingText?: string;
@@ -54,7 +61,7 @@ export class InfiniteScrollContent implements ComponentInterface {
)}
{this.loadingText && (
-
+
)}
);
diff --git a/core/src/components/infinite-scroll-content/readme.md b/core/src/components/infinite-scroll-content/readme.md
index 04b3649ec8..f0f8d980a1 100644
--- a/core/src/components/infinite-scroll-content/readme.md
+++ b/core/src/components/infinite-scroll-content/readme.md
@@ -76,10 +76,10 @@ export default Example
## Properties
-| Property | Attribute | Description | Type | Default |
-| ---------------- | ----------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------- |
-| `loadingSpinner` | `loading-spinner` | An animated SVG spinner that shows while loading. | `"bubbles" \| "circles" \| "crescent" \| "dots" \| "lines" \| "lines-small" \| null \| undefined` | `undefined` |
-| `loadingText` | `loading-text` | Optional text to display while loading. | `string \| undefined` | `undefined` |
+| Property | Attribute | Description | Type | Default |
+| ---------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------- |
+| `loadingSpinner` | `loading-spinner` | An animated SVG spinner that shows while loading. | `"bubbles" \| "circles" \| "crescent" \| "dots" \| "lines" \| "lines-small" \| null \| undefined` | `undefined` |
+| `loadingText` | `loading-text` | 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) | `string \| undefined` | `undefined` |
----------------------------------------------
diff --git a/core/src/components/refresher-content/readme.md b/core/src/components/refresher-content/readme.md
index d936d71b15..2d8c0fef80 100644
--- a/core/src/components/refresher-content/readme.md
+++ b/core/src/components/refresher-content/readme.md
@@ -9,12 +9,12 @@ The refresher content contains the text, icon and spinner to display during a pu
## Properties
-| Property | Attribute | Description | Type | Default |
-| ------------------- | -------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------- |
-| `pullingIcon` | `pulling-icon` | A static icon to display when you begin to pull down | `null \| string \| undefined` | `undefined` |
-| `pullingText` | `pulling-text` | The text you want to display when you begin to pull down | `string \| undefined` | `undefined` |
-| `refreshingSpinner` | `refreshing-spinner` | An animated SVG spinner that shows when refreshing begins | `"bubbles" \| "circles" \| "crescent" \| "dots" \| "lines" \| "lines-small" \| null \| undefined` | `undefined` |
-| `refreshingText` | `refreshing-text` | The text you want to display when performing a refresh | `string \| undefined` | `undefined` |
+| Property | Attribute | Description | Type | Default |
+| ------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------- |
+| `pullingIcon` | `pulling-icon` | A static icon to display when you begin to pull down | `null \| string \| undefined` | `undefined` |
+| `pullingText` | `pulling-text` | 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) | `string \| undefined` | `undefined` |
+| `refreshingSpinner` | `refreshing-spinner` | An animated SVG spinner that shows when refreshing begins | `"bubbles" \| "circles" \| "crescent" \| "dots" \| "lines" \| "lines-small" \| null \| undefined` | `undefined` |
+| `refreshingText` | `refreshing-text` | 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 `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) | `string \| undefined` | `undefined` |
----------------------------------------------
diff --git a/core/src/components/refresher-content/refresher-content.tsx b/core/src/components/refresher-content/refresher-content.tsx
index 2cbbd3ff17..8e08642899 100644
--- a/core/src/components/refresher-content/refresher-content.tsx
+++ b/core/src/components/refresher-content/refresher-content.tsx
@@ -1,6 +1,7 @@
import { Component, ComponentInterface, Prop } from '@stencil/core';
import { Config, Mode, SpinnerTypes } from '../../interface';
+import { sanitizeDOMString } from '../../utils/sanitization';
@Component({
tag: 'ion-refresher-content'
@@ -17,7 +18,13 @@ export class RefresherContent implements ComponentInterface {
@Prop({ mutable: true }) pullingIcon?: string | null;
/**
- * The text you want to display when you begin to pull down
+ * 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 `` would become
+ * `<Ionic>`
+ *
+ * For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
@Prop() pullingText?: string;
@@ -27,7 +34,13 @@ export class RefresherContent implements ComponentInterface {
@Prop({ mutable: true }) refreshingSpinner?: SpinnerTypes | null;
/**
- * The text you want to display when performing a refresh
+ * 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 `` would become
+ * `<Ionic>`
+ *
+ * For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
@Prop() refreshingText?: string;
@@ -60,7 +73,7 @@ export class RefresherContent implements ComponentInterface {
}
{this.pullingText &&
-
+
}
,
@@ -70,7 +83,7 @@ export class RefresherContent implements ComponentInterface {
}
{this.refreshingText &&
-
+
}
];
diff --git a/core/src/components/searchbar/readme.md b/core/src/components/searchbar/readme.md
index 6a9c167ed1..c86beb046c 100644
--- a/core/src/components/searchbar/readme.md
+++ b/core/src/components/searchbar/readme.md
@@ -162,23 +162,23 @@ export default Example;
## Properties
-| Property | Attribute | Description | Type | Default |
-| ------------------ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------- |
-| `animated` | `animated` | If `true`, enable searchbar animation. | `boolean` | `false` |
-| `autocomplete` | `autocomplete` | Set the input's autocomplete property. | `"off" \| "on"` | `'off'` |
-| `autocorrect` | `autocorrect` | Set the input's autocorrect property. | `"off" \| "on"` | `'off'` |
-| `cancelButtonIcon` | `cancel-button-icon` | Set the cancel button icon. Only applies to `md` mode. | `string` | `'md-arrow-back'` |
-| `cancelButtonText` | `cancel-button-text` | Set the the cancel button text. Only applies to `ios` mode. | `string` | `'Cancel'` |
-| `clearIcon` | `clear-icon` | Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close"` for `md`. | `string \| undefined` | `undefined` |
-| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
-| `debounce` | `debounce` | Set the amount of time, in milliseconds, to wait to trigger the `ionChange` event after each keystroke. | `number` | `250` |
-| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
-| `placeholder` | `placeholder` | Set the input's placeholder. | `string` | `'Search'` |
-| `searchIcon` | `search-icon` | The icon to use as the search icon. | `string` | `'search'` |
-| `showCancelButton` | `show-cancel-button` | If `true`, show the cancel button. | `boolean` | `false` |
-| `spellcheck` | `spellcheck` | If `true`, enable spellcheck on the input. | `boolean` | `false` |
-| `type` | `type` | Set the type of the input. | `"email" \| "number" \| "password" \| "search" \| "tel" \| "text" \| "url"` | `'search'` |
-| `value` | `value` | the value of the searchbar. | `null \| string \| undefined` | `''` |
+| Property | Attribute | Description | Type | Default |
+| ------------------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | ----------------- |
+| `animated` | `animated` | If `true`, enable searchbar animation. | `boolean` | `false` |
+| `autocomplete` | `autocomplete` | Set the input's autocomplete property. | `"off" \| "on"` | `'off'` |
+| `autocorrect` | `autocorrect` | Set the input's autocorrect property. | `"off" \| "on"` | `'off'` |
+| `cancelButtonIcon` | `cancel-button-icon` | Set the cancel button icon. Only applies to `md` mode. | `string` | `'md-arrow-back'` |
+| `cancelButtonText` | `cancel-button-text` | Set the the cancel button text. Only applies to `ios` mode. | `string` | `'Cancel'` |
+| `clearIcon` | `clear-icon` | Set the clear icon. Defaults to `"close-circle"` for `ios` and `"close"` for `md`. | `string \| undefined` | `undefined` |
+| `color` | `color` | The color to use from your application's color palette. Default options are: `"primary"`, `"secondary"`, `"tertiary"`, `"success"`, `"warning"`, `"danger"`, `"light"`, `"medium"`, and `"dark"`. For more information on colors, see [theming](/docs/theming/basics). | `string \| undefined` | `undefined` |
+| `debounce` | `debounce` | Set the amount of time, in milliseconds, to wait to trigger the `ionChange` event after each keystroke. | `number` | `250` |
+| `mode` | `mode` | The mode determines which platform styles to use. | `"ios" \| "md"` | `undefined` |
+| `placeholder` | `placeholder` | Set the input's placeholder. `placeholder` can accept either plaintext or HTML as a string. To display characters normally reserved for HTML, they must be escaped. For example `` would become `<Ionic>` For more information: [Security Documentation](https://ionicframework.com/docs/faq/security) | `string` | `'Search'` |
+| `searchIcon` | `search-icon` | The icon to use as the search icon. | `string` | `'search'` |
+| `showCancelButton` | `show-cancel-button` | If `true`, show the cancel button. | `boolean` | `false` |
+| `spellcheck` | `spellcheck` | If `true`, enable spellcheck on the input. | `boolean` | `false` |
+| `type` | `type` | Set the type of the input. | `"email" \| "number" \| "password" \| "search" \| "tel" \| "text" \| "url"` | `'search'` |
+| `value` | `value` | the value of the searchbar. | `null \| string \| undefined` | `''` |
## Events
diff --git a/core/src/components/searchbar/searchbar.tsx b/core/src/components/searchbar/searchbar.tsx
index 1645a2b2aa..b85569ed9d 100644
--- a/core/src/components/searchbar/searchbar.tsx
+++ b/core/src/components/searchbar/searchbar.tsx
@@ -2,6 +2,7 @@ import { Component, ComponentInterface, Element, Event, EventEmitter, Method, Pr
import { Color, Config, Mode, SearchbarChangeEventDetail } from '../../interface';
import { debounceEvent } from '../../utils/helpers';
+import { sanitizeDOMString } from '../../utils/sanitization';
import { createColorClasses } from '../../utils/theme';
@Component({
@@ -80,6 +81,12 @@ export class Searchbar implements ComponentInterface {
/**
* Set the input's placeholder.
+ * `placeholder` can accept either plaintext or HTML as a string.
+ * To display characters normally reserved for HTML, they
+ * must be escaped. For example `` would become
+ * `<Ionic>`
+ *
+ * For more information: [Security Documentation](https://ionicframework.com/docs/faq/security)
*/
@Prop() placeholder = 'Search';
@@ -288,7 +295,7 @@ export class Searchbar implements ComponentInterface {
// Create a dummy span to get the placeholder width
const doc = this.doc;
const tempSpan = doc.createElement('span');
- tempSpan.innerHTML = this.placeholder;
+ tempSpan.innerHTML = sanitizeDOMString(this.placeholder) || '';
doc.body.appendChild(tempSpan);
// Get the width of the span then remove it
diff --git a/core/src/utils/sanitization/index.ts b/core/src/utils/sanitization/index.ts
new file mode 100644
index 0000000000..3019250f0d
--- /dev/null
+++ b/core/src/utils/sanitization/index.ts
@@ -0,0 +1,126 @@
+/**
+ * Does a simple sanitization of all elements
+ * in an untrusted string
+ */
+
+export const sanitizeDOMString = (untrustedString: string | undefined): string | undefined => {
+ try {
+ if (typeof untrustedString !== 'string' || untrustedString === '') { return untrustedString; }
+
+ /**
+ * Create a document fragment
+ * separate from the main DOM,
+ * create a div to do our work in
+ */
+ const documentFragment = document.createDocumentFragment();
+ const workingDiv = document.createElement('div');
+ documentFragment.appendChild(workingDiv);
+ workingDiv.innerHTML = untrustedString;
+
+ /**
+ * Remove any elements
+ * that are blocked
+ */
+ blockedTags.forEach(blockedTag => {
+
+ const getElementsToRemove = documentFragment.querySelectorAll(blockedTag);
+ for (let elementIndex = getElementsToRemove.length - 1; elementIndex >= 0; elementIndex--) {
+ const element = getElementsToRemove[elementIndex];
+ if (element.parentNode) {
+ element.parentNode.removeChild(element);
+ } else {
+ documentFragment.removeChild(element);
+ }
+
+ /**
+ * We still need to sanitize
+ * the children of this element
+ * as they are left behind
+ */
+ const childElements = getElementChildren(element);
+
+ /* tslint:disable-next-line */
+ for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
+ sanitizeElement(childElements[childIndex]);
+ }
+ }
+ });
+
+ /**
+ * Go through remaining elements and remove
+ * non-allowed attribs
+ */
+
+ // IE does not support .children on document fragments, only .childNodes
+ const documentFragmentChildren = getElementChildren(documentFragment);
+
+ /* tslint:disable-next-line */
+ for (let childIndex = 0; childIndex < documentFragmentChildren.length; childIndex++) {
+ sanitizeElement(documentFragmentChildren[childIndex]);
+ }
+
+ // Append document fragment to div
+ const fragmentDiv = document.createElement('div');
+ fragmentDiv.appendChild(documentFragment);
+
+ // First child is always the div we did our work in
+ const getInnerDiv = fragmentDiv.querySelector('div');
+ return (getInnerDiv !== null) ? getInnerDiv.innerHTML : fragmentDiv.innerHTML;
+
+ } catch (err) {
+ console.error(err);
+
+ return '';
+ }
+};
+
+/**
+ * Clean up current element based on allowed attributes
+ * and then recursively dig down into any child elements to
+ * clean those up as well
+ */
+const sanitizeElement = (element: any) => {
+ // IE uses childNodes, so ignore nodes that are not elements
+ if (element.nodeType && element.nodeType !== 1) { return; }
+
+ for (let i = element.attributes.length - 1; i >= 0; i--) {
+ const attribute = element.attributes[i];
+ const attributeName = attribute.name;
+
+ // remove non-allowed attribs
+ if (!allowedAttributes.includes(attributeName.toLowerCase())) {
+ element.removeAttribute(attributeName);
+ continue;
+ }
+
+ // clean up any allowed attribs
+ // that attempt to do any JS funny-business
+ const attributeValue = attribute.value;
+
+ /* tslint:disable-next-line */
+ if (attributeValue != null && attributeValue.toLowerCase().includes('javascript:')) {
+ element.removeAttribute(attributeName);
+ }
+ }
+
+ /**
+ * Sanitize any nested children
+ */
+ const childElements = getElementChildren(element);
+
+ /* tslint:disable-next-line */
+ for (let i = 0; i < childElements.length; i++) {
+ sanitizeElement(childElements[i]);
+ }
+};
+
+/**
+ * IE doesn't always support .children
+ * so we revert to .childNodes instead
+ */
+const getElementChildren = (element: any) => {
+ return (element.children != null) ? element.children : element.childNodes;
+};
+
+const allowedAttributes = ['class', 'id', 'href', 'src'];
+const blockedTags = ['script', 'style', 'iframe', 'meta', 'link', 'object', 'embed'];
diff --git a/core/src/utils/sanitization/test/e2e.ts b/core/src/utils/sanitization/test/e2e.ts
new file mode 100644
index 0000000000..513946f573
--- /dev/null
+++ b/core/src/utils/sanitization/test/e2e.ts
@@ -0,0 +1,26 @@
+import { newE2EPage } from '@stencil/core/testing';
+
+test('sanitization:', async done => {
+
+ const page = await newE2EPage({
+ url: '/src/utils/sanitization/test?ionic:_testing=true'
+ });
+
+ page.on('pageerror', (err: any) => {
+ if (err.message.includes('sanitizeFailed')) {
+ done.fail(new Error('Failed to properly sanitize'));
+ }
+ });
+
+ await page.click('#testA');
+ await page.click('#testB');
+ await page.click('#testC');
+ await page.click('#testD');
+ await page.click('#testE');
+ await page.click('#testF');
+ await page.click('#testG');
+ await page.click('#testH');
+
+ done();
+
+});
diff --git a/core/src/utils/sanitization/test/index.html b/core/src/utils/sanitization/test/index.html
new file mode 100644
index 0000000000..fed2f3b7a5
--- /dev/null
+++ b/core/src/utils/sanitization/test/index.html
@@ -0,0 +1,113 @@
+
+
+
+
+ Sanitization
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Sanitization
+
+
+
+
+
Results will appear here
+
+ Test A
+ Test B
+ Test C
+ Test D
+ Test E
+ Test F
+ Test G
+ Test H
+
+
+
+
+
+
+
+
diff --git a/docs/package.json b/docs/package.json
index 014e091dfd..d0234bfa15 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/docs",
- "version": "4.3.0",
+ "version": "4.3.1",
"description": "Pre-packaged API documentation for the Ionic docs.",
"main": "core.json",
"files": [