diff --git a/__tests__/serializers/slateToHtml/index.spec.ts b/__tests__/serializers/slateToHtml/index.spec.ts
index f51df3b..4509c63 100644
--- a/__tests__/serializers/slateToHtml/index.spec.ts
+++ b/__tests__/serializers/slateToHtml/index.spec.ts
@@ -1,4 +1,4 @@
-import { ChildNode, Element } from 'domhandler'
+import { Element } from 'domhandler'
import { slateToHtml, slateToDomConfig } from '../../../src'
describe('slateToHtml expected behaviour', () => {
@@ -17,6 +17,69 @@ describe('slateToHtml expected behaviour', () => {
expect(slateToHtml(slate)).toEqual(html)
})
+ /**
+ * @see https://www.w3.org/International/questions/qa-escapes#use
+ */
+ it('encodes `breaking` HTML entities', () => {
+ const html = `
2 > 1 but is < 3 & it can break HTML
`
+ const slate = [
+ {
+ children: [
+ {
+ text: "2 > 1 but is < 3 & it can break HTML",
+ },
+ ],
+ type: 'p',
+ },
+ ]
+ expect(slateToHtml(slate)).toEqual(html)
+ })
+
+ it('encodes `non breaking` HTML entities', () => {
+ const html = `The company’s priority is 'inside sales' and changing the spelling of cafe to café.
`
+ const slate = [
+ {
+ children: [
+ {
+ text: "The company’s priority is 'inside sales' and changing the spelling of cafe to café.",
+ },
+ ],
+ type: 'p',
+ },
+ ]
+ expect(slateToHtml(slate)).toEqual(html)
+ })
+
+ it('encodes `breaking` HTML entities only if option is active', () => {
+ const html = `2 > 1 but is < 3 & it can break HTML
The company’s priority is 'inside sales' and changing the spelling of cafe to café.
`
+ const slate = [
+ {
+ children: [
+ {
+ text: "2 > 1 but is < 3 & it can break HTML",
+ },
+ ],
+ type: 'p',
+ },
+ {
+ children: [
+ {
+ text: "The company’s priority is 'inside sales' and changing the spelling of cafe to café.",
+ },
+ ],
+ type: 'p',
+ },
+ ]
+ expect(slateToHtml(
+ slate,
+ {
+ ...slateToDomConfig,
+ encodeEntities: false,
+ alwaysEncodeBreakingEntities: true,
+ }
+ )).toEqual(html)
+ })
+
it('does not encode HTML entities with the appropriate option', () => {
const html = `What's Heading 1
`
const slate = [
diff --git a/src/config/slateToDom/default.ts b/src/config/slateToDom/default.ts
index 845f4e3..892dd2b 100644
--- a/src/config/slateToDom/default.ts
+++ b/src/config/slateToDom/default.ts
@@ -51,6 +51,7 @@ export const config: Config = {
},
},
encodeEntities: true,
+ alwaysEncodeBreakingEntities: false,
alwaysEncodeCodeEntities: false,
convertLineBreakToBr: false,
}
diff --git a/src/config/slateToDom/types.ts b/src/config/slateToDom/types.ts
index 9185c9c..1b010c5 100644
--- a/src/config/slateToDom/types.ts
+++ b/src/config/slateToDom/types.ts
@@ -21,6 +21,7 @@ export interface Config {
elementTransforms: ElementTagTransform
defaultTag?: string
encodeEntities?: boolean
+ alwaysEncodeBreakingEntities?: boolean
alwaysEncodeCodeEntities?: boolean
convertLineBreakToBr?: boolean
}
diff --git a/src/serializers/slateToHtml/index.ts b/src/serializers/slateToHtml/index.ts
index d169031..aad9d64 100644
--- a/src/serializers/slateToHtml/index.ts
+++ b/src/serializers/slateToHtml/index.ts
@@ -6,7 +6,7 @@ import { Text as SlateText } from 'slate'
import { config as defaultConfig } from '../../config/slateToDom/default'
import { nestedMarkElements } from '../../utilities/domhandler'
-import { getNested, isEmptyObject, styleToString } from '../../utilities'
+import { getNested, isEmptyObject, styleToString, encodeBreakingEntities } from '../../utilities'
import { SlateToDomConfig } from '../..'
import { isBlock } from '../blocks'
@@ -30,7 +30,7 @@ export const slateToDom: SlateToDom = (node: any[], config = defaultConfig) => {
const slateNodeToHtml = (node: any, config = defaultConfig, isLastNodeInDocument = false) => {
if (SlateText.isText(node)) {
- const str = node.text
+ const str = (config.alwaysEncodeBreakingEntities && config.encodeEntities === false) ? encodeBreakingEntities(node.text) : node.text
// convert line breaks to br tags
const strLines = config.convertLineBreakToBr ? str.split('\n') : [str]
diff --git a/src/utilities/index.ts b/src/utilities/index.ts
index 5b3cad5..cb3c5b0 100644
--- a/src/utilities/index.ts
+++ b/src/utilities/index.ts
@@ -62,3 +62,23 @@ export const removeEmpty = (obj: {}): {} => {
export const getNested = (obj: any, ...args: string[]) => {
return args.reduce((o, level) => o && o[level], obj)
}
+
+export const encodeBreakingEntities = (str: string) => {
+ const swapChar = (charToSwap: string) => { // that swaps characters to HTML entities
+ switch(charToSwap){
+ case "&":
+ return "&"
+ case "<":
+ return "<"
+ case ">":
+ return ">"
+ default:
+ return charToSwap
+ }
+ }
+ str = str.replace(/[&<>]/g, function(match){
+ return swapChar(match)
+ })
+
+ return str
+}
\ No newline at end of file