Skip to content

Commit 1c18b5e

Browse files
committed
feat: support for nested attrs
1 parent 3085336 commit 1c18b5e

File tree

5 files changed

+56
-8
lines changed

5 files changed

+56
-8
lines changed

src/fromRedactor.tsx

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,14 @@ export const fromRedactor = (el: any, options?:IHtmlToJsonOptions) : IAnyObject
232232
return jsx('element', { type: "doc", uid: generateId(), attrs: {} }, children)
233233
}
234234
if (options?.allowNonStandardTags && !Object.keys(ELEMENT_TAGS).includes(nodeName) && !Object.keys(TEXT_TAGS).includes(nodeName)) {
235-
const attributes = el.attributes
236-
const attribute = {}
237-
Array.from(attributes).forEach((child: any) => {
238-
attribute[child.nodeName] = child.nodeValue
235+
const attributes = (el as HTMLElement).attributes
236+
const attributeMap = {}
237+
Array.from(attributes).forEach((attribute) => {
238+
let { nodeName, value } = attribute
239+
attributeMap[nodeName] = getNestedValueIfAvailable(value)
239240
})
240241
console.warn(`${nodeName} is not a standard tag of JSON RTE.`)
241-
return jsx('element', { type: nodeName.toLowerCase(), attrs: { ...attribute } }, children)
242+
return jsx('element', { type: nodeName.toLowerCase(), attrs: { ...attributeMap } }, children)
242243
}
243244
const isEmbedEntry = el.attributes['data-sys-entry-uid']?.value
244245
const type = el.attributes['type']?.value
@@ -791,4 +792,15 @@ const getFinalImageAttributes = ({elementAttrs, newChildren, extraAttrs, sizeAtt
791792
const imageAttrs = getImageAttributes(elementAttrs, childAttrs, extraAttrs);
792793

793794
return imageAttrs
794-
}
795+
}
796+
797+
const getNestedValueIfAvailable = (value: string) => {
798+
try {
799+
if (typeof value === "string" && value.match(/^{|\[/i)) {
800+
return JSON.parse(value);
801+
}
802+
return value
803+
} catch {
804+
return value;
805+
}
806+
};

src/toRedactor.tsx

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import kebbab from 'lodash/kebabCase'
22
import isEmpty from 'lodash/isEmpty'
33

44
import {IJsonToHtmlElementTags, IJsonToHtmlOptions, IJsonToHtmlTextTags} from './types'
5+
import { isPlainObject } from 'lodash'
56

67
const ELEMENT_TYPES: IJsonToHtmlElementTags = {
78
'blockquote': (attrs: string, child: string) => {
@@ -223,7 +224,13 @@ export const toRedactor = (jsonValue: any,options?:IJsonToHtmlOptions) : string
223224
if (options?.allowNonStandardTypes && !Object.keys(ELEMENT_TYPES).includes(jsonValue['type']) && jsonValue['type'] !== 'doc') {
224225
let attrs = ''
225226
Object.entries(jsonValue?.attrs|| {}).forEach(([key, val]) => {
226-
attrs += val ? ` ${key}="${val}"` : ` ${key}`;
227+
if(isPlainObject(val)){
228+
val = JSON.stringify(val)
229+
attrs += ` ${key}='${val}'`
230+
}
231+
else{
232+
attrs += val ? ` ${key}="${val}"` : ` ${key}`;
233+
}
227234
})
228235
attrs = (attrs.trim() ? ' ' : '') + attrs.trim()
229236
console.warn(`${jsonValue['type']} is not a valid element type.`)

test/expectedJson.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1745,5 +1745,15 @@ export default {
17451745
]
17461746
}
17471747
]
1748-
}
1748+
},
1749+
"nested-attrs": [
1750+
{
1751+
json: {"type":"doc","uid":"uid","attrs":{},"children":[{"type":"hangout-module","attrs":{},"children":[{"type":"hangout-chat","attrs":{"from":"Paul, Addy","nested":{"to":"JD"}},"children":[{"type":"hangout-discussion","attrs":{},"children":[{"type":"hangout-message","attrs":{"from":"Paul","profile":"profile.png","datetime":"2013-07-17T12:02"},"children":[{"type":"p","uid":"uid","attrs":{},"children":[{"text":"Feelin' this Web Components thing."}]},{"type":"p","uid":"uid","attrs":{},"children":[{"text":"Heard of it?"}]}]}]}]},{"type":"hangout-chat","attrs":{},"children":[{"text":"Hi There!"}]}]}]},
1752+
html : `<hangout-module><hangout-chat from="Paul, Addy" nested='{"to":"JD"}'><hangout-discussion><hangout-message from="Paul" profile="profile.png" datetime="2013-07-17T12:02"><p>Feelin' this Web Components thing.</p><p>Heard of it?</p></hangout-message></hangout-discussion></hangout-chat><hangout-chat>Hi There!</hangout-chat></hangout-module>`
1753+
},
1754+
{
1755+
json: {"type":"doc","uid":"uid","attrs":{},"children":[{"type":"hangout-module","attrs":{},"children":[{"type":"hangout-chat","attrs":{"from":"Paul, Addy","nested-json":{"to":"Hello World","more-nesting":{"from":"Beautiful World"}}},"children":[{"type":"hangout-discussion","attrs":{},"children":[{"type":"hangout-message","attrs":{"from":"Paul","profile":"profile.png","datetime":"2013-07-17T12:02"},"children":[{"type":"p","uid":"uid","attrs":{},"children":[{"text":"Feelin' this Web Components thing."}]},{"type":"p","uid":"uid","attrs":{},"children":[{"text":"Heard of it?"}]}]}]}]},{"type":"hangout-chat","attrs":{},"children":[{"text":"Hi There!"}]}]}]},
1756+
html : `<hangout-module><hangout-chat from="Paul, Addy" nested-json='{"to":"Hello World","more-nesting":{"from":"Beautiful World"}}'><hangout-discussion><hangout-message from="Paul" profile="profile.png" datetime="2013-07-17T12:02"><p>Feelin' this Web Components thing.</p><p>Heard of it?</p></hangout-message></hangout-discussion></hangout-chat><hangout-chat>Hi There!</hangout-chat></hangout-module>`
1757+
},
1758+
]
17491759
}

test/fromRedactor.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ const docWrapper = (children: any) => {
1515
const compareValue = (json1,json2) => {
1616
return isEqual(JSON.stringify(omitdeep(json1, "uid")), JSON.stringify(omitdeep(docWrapper(json2), "uid")))
1717
}
18+
19+
jest.mock('uuid', () => ({ v4: () => 'uid' }));
1820
describe("Testing html to json conversion", () => {
1921
it("paragraph conversion", () => {
2022
let html = "<p>This is test</p>"
@@ -224,4 +226,14 @@ describe("Testing html to json conversion", () => {
224226
], "type": "p" }]))
225227
expect(testResult).toBe(true)
226228
})
229+
230+
test("should convert stringified attrs to proper nested JSON attrs", () => {
231+
for (const testCase of expectedValue["nested-attrs"]) {
232+
const { json, html } = testCase;
233+
const dom = new JSDOM(html);
234+
let htmlDoc = dom.window.document.querySelector("body");
235+
const jsonValue = fromRedactor(htmlDoc, { allowNonStandardTags: true });
236+
expect(jsonValue).toStrictEqual(json);
237+
}
238+
});
227239
})

test/toRedactor.test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,11 @@ describe("Testing json to html conversion", () => {
122122
let testResult = isEqual(htmlValue, expectedValue["inline-classname-and-id"].html)
123123
expect(testResult).toBe(true)
124124
})
125+
test("should have stringified attrs for nested json", () => {
126+
for (const testCase of expectedValue["nested-attrs"]) {
127+
const { json, html } = testCase;
128+
const htmlValue = toRedactor(json, { allowNonStandardTypes: true });
129+
expect(htmlValue).toBe(html);
130+
}
131+
});
125132
})

0 commit comments

Comments
 (0)