Skip to content

Commit 6ed8ced

Browse files
authored
fix: assigning text to textContent should be html decoded, fixes #417 (#418)
1 parent 6ccbb5a commit 6ed8ced

File tree

3 files changed

+22
-4
lines changed

3 files changed

+22
-4
lines changed

packages/multiple-select-vanilla/src/MultipleSelectInstance.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
getComputedSize,
1919
getOffset,
2020
getSize,
21+
htmlDecode,
2122
insertAfter,
2223
toggleElement,
2324
} from './utils/domUtils.js';
@@ -1487,7 +1488,7 @@ export class MultipleSelectInstance {
14871488
if (this.isRenderAsHtml) {
14881489
elmOrProp.innerHTML = (typeof this.options.sanitizer === 'function' ? this.options.sanitizer(value) : value) as unknown as string;
14891490
} else {
1490-
elmOrProp.textContent = value;
1491+
elmOrProp.textContent = htmlDecode(value);
14911492
}
14921493
}
14931494

packages/multiple-select-vanilla/src/utils/domUtils.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { HtmlStruct, InferDOMType } from '../models/interfaces.js';
2-
import { objectRemoveEmptyProps } from './utils.js';
2+
import { isDefined, objectRemoveEmptyProps } from './utils.js';
33

44
export interface HtmlElementPosition {
55
top: number;
@@ -228,6 +228,23 @@ export function findParent(elm: HTMLElement, selector: string) {
228228
return targetElm;
229229
}
230230

231+
/**
232+
* Simple function to decode the most common HTML entities.
233+
* For example: "&lt;div&gt;Hablar espa&#241;ol? &#55358;&#56708;&lt;/div&gt;" => "<div>Hablar español? 🦄</div>"
234+
* @param {String} inputValue - input value to be decoded
235+
* @return {String}
236+
*/
237+
export function htmlDecode(input?: string | boolean | number): string {
238+
if (isDefined(input)) {
239+
// 1. decode html entities (e.g. `&#39;` => single quote)
240+
// 2. use textarea to decode the rest (e.g. html tags and symbols, `&lt;div&gt;` => `<div>`)
241+
const txt = document.createElement('textarea');
242+
txt.innerHTML = input.toString().replace(/&#(\d+);/g, (_, dec) => String.fromCharCode(dec));
243+
return txt.value;
244+
}
245+
return '';
246+
}
247+
231248
export function insertAfter(referenceNode: HTMLElement, newNode: HTMLElement) {
232249
referenceNode.parentNode?.insertBefore(newNode, referenceNode.nextSibling);
233250
}

packages/multiple-select-vanilla/src/utils/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@ export function deepCopy<T = any>(obj: T): T {
3333
return Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, deepCopy(value)])) as T;
3434
}
3535

36-
export function isDefined(val: any) {
37-
return val !== undefined && val !== null && val !== '';
36+
export function isDefined<T>(value: T | undefined | null): value is T {
37+
return <T>value !== undefined && <T>value !== null && <T>value !== '';
3838
}
3939

4040
/**

0 commit comments

Comments
 (0)