Skip to content

Commit

Permalink
Merge pull request #54 from contentstack/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
Jayesh2812 committed Aug 9, 2024
2 parents 48a8edd + 3aa9b03 commit 5cdf53f
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 52 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@contentstack/json-rte-serializer",
"version": "2.0.8",
"version": "2.0.9",
"description": "This Package converts Html Document to Json and vice-versa.",
"main": "lib/index.js",
"module": "lib/index.mjs",
Expand Down
47 changes: 38 additions & 9 deletions src/fromRedactor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ const traverseChildAndModifyChild = (element: any, attrsForChild: any) => {
Array.from(element.children || []).map((el) => traverseChildAndModifyChild(el, attrsForChild)).flat()
return
}
const traverseChildAndWarpChild = (children: Array<Object>) => {
const traverseChildAndWarpChild = (children: Array<Object>, allowNonStandardTags: boolean = false) => {
let inlineElementIndex: Array<number> = []
let hasBlockElement = false
let childrenCopy = cloneDeep(children)
Expand All @@ -164,6 +164,9 @@ const traverseChildAndWarpChild = (children: Array<Object>) => {
} else {
inlineElementIndex.push(index)
}
}
else if (allowNonStandardTags && child?.attrs?.inline) {
inlineElementIndex.push(index)
} else {
hasBlockElement = true
}
Expand Down Expand Up @@ -191,6 +194,8 @@ export const fromRedactor = (el: any, options?:IHtmlToJsonOptions) : IAnyObject
}
if (el.parentNode.nodeName === 'SPAN') {
let attrs = { style: {} }
const metadata = {}

if (el.parentNode.style?.color) {
attrs = {
...attrs,
Expand Down Expand Up @@ -218,7 +223,20 @@ export const fromRedactor = (el: any, options?:IHtmlToJsonOptions) : IAnyObject
}
}
}
return jsx('text', { attrs: attrs }, el.textContent)
if(el.parentNode.getAttribute("id")){
metadata['id'] = el.parentNode.getAttribute("id")
el.parentNode.removeAttribute("id")
}
if(el.parentNode.getAttribute("class")){
metadata['classname'] = el.parentNode.getAttribute("class")
el.parentNode.removeAttribute("class")
}

if(!isEmpty(attrs.style)){
metadata['attrs'] = attrs
}

return jsx('text', metadata, el.textContent)
}
return el.textContent
} else if (el.nodeType !== 1) {
Expand Down Expand Up @@ -264,7 +282,7 @@ export const fromRedactor = (el: any, options?:IHtmlToJsonOptions) : IAnyObject
}
let children: any = flatten(Array.from(parent.childNodes).map((child) => fromRedactor(child, options)))
children = children.filter((child: any) => child !== null)
children = traverseChildAndWarpChild(children)
children = traverseChildAndWarpChild(children, options?.allowNonStandardTags)
if (children.length === 0) {
children = [{ text: '' }]
}
Expand Down Expand Up @@ -482,6 +500,9 @@ export const fromRedactor = (el: any, options?:IHtmlToJsonOptions) : IAnyObject
]
)
}
if(el.parentNode?.nodeName === 'FIGURE'){
return children
}
}

if (ELEMENT_TAGS[nodeName]) {
Expand Down Expand Up @@ -804,7 +825,7 @@ export const fromRedactor = (el: any, options?:IHtmlToJsonOptions) : IAnyObject
}
let noOfInlineElement = 0
Array.from(el.parentNode?.childNodes || []).forEach((child: any) => {
if (child.nodeType === 3 || child.nodeName === 'SPAN' || child.nodeName === 'A') {
if (child.nodeType === 3 || child.nodeName === 'SPAN' || child.nodeName === 'A' || (options?.allowNonStandardTags && child.getAttribute('inline'))) {
noOfInlineElement += 1
}
})
Expand All @@ -817,6 +838,9 @@ export const fromRedactor = (el: any, options?:IHtmlToJsonOptions) : IAnyObject
uid: generateId()
}
}
if (noOfInlineElement === el.parentNode?.childNodes.length && Array.from(el.attributes).length === 0) {
return children
}
}

if (children.length === 0) {
Expand Down Expand Up @@ -856,7 +880,7 @@ const getImageAttributes = (elementAttrs: any, childAttrs: any, extraAttrs: any)
...extraAttrs
},
"asset-caption": extraAttrs["asset-caption"],
"link": extraAttrs.link
"link": extraAttrs.link ?? extraAttrs.anchorLink
}
}
if (elementAttrs?.attrs?.["redactor-attributes"]?.link) {
Expand All @@ -873,11 +897,16 @@ const getImageAttributes = (elementAttrs: any, childAttrs: any, extraAttrs: any)

const getReferenceAttributes = ({elementAttrs, newChildren, extraAttrs, sizeAttrs} : any) => {

let { style } = elementAttrs.attrs;

extraAttrs['asset-caption'] = extraAttrs['caption'];
if(newChildren[0].attrs.width){
delete sizeAttrs.width
}
const style = {}
if (elementAttrs?.attrs?.style?.['text-align']) {
style['text-align'] = elementAttrs?.attrs?.style?.['text-align']
}

const childAttrs = { ...newChildren[0].attrs, ...sizeAttrs, style: { 'text-align': style['text-align'] }, position: extraAttrs.position }
const childAttrs = { ...newChildren[0].attrs, ...sizeAttrs, style , position: extraAttrs.position }
extraAttrs = { ...extraAttrs, ...sizeAttrs }

if (!childAttrs.position) {
Expand All @@ -887,7 +916,7 @@ const getReferenceAttributes = ({elementAttrs, newChildren, extraAttrs, sizeAttr
const referenceAttrs = getImageAttributes(elementAttrs, childAttrs, extraAttrs);

referenceAttrs.type = "reference";

delete referenceAttrs?.attrs?.['redactor-attributes']?.['anchorlink'];
return referenceAttrs
}

Expand Down
13 changes: 9 additions & 4 deletions src/toRedactor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ const ELEMENT_TYPES: IJsonToHtmlElementTags = {
}

else if (extraAttrs?.displayType === "display") {
const anchor = jsonBlock?.["attrs"]?.["link"];
const anchor = jsonBlock?.["attrs"]?.["link"] ?? jsonBlock?.["attrs"]?.["anchorLink"];

const caption = jsonBlock?.["attrs"]?.["asset-caption"];
const position = jsonBlock?.["attrs"]?.["position"];
Expand All @@ -134,7 +134,9 @@ const ELEMENT_TYPES: IJsonToHtmlElementTags = {
const figureStyles = {
margin: "0",
};
attrs = ` src="${jsonBlock?.["attrs"]?.["asset-link"]}"` + attrs;
if(!attrs.includes(`src="${jsonBlock?.["attrs"]?.["asset-link"]}`)){
attrs = ` src="${jsonBlock?.["attrs"]?.["asset-link"]}"` + attrs;
}
let img = `<img${attrs}/>`;

if (anchor) {
Expand Down Expand Up @@ -384,9 +386,9 @@ export const toRedactor = (jsonValue: any,options?:IJsonToHtmlOptions) : string
let width = String(allattrs['width'])

if (width.slice(width.length - 1) === '%') {
allattrs['width'] = String(allattrs['width'])
} else {
allattrs['width'] = allattrs['width'] + '%'
} else {
allattrs['width'] = String(allattrs['width'])
}
// style = `width: ${allattrs['width']}; height: auto;`
}
Expand Down Expand Up @@ -478,6 +480,9 @@ export const toRedactor = (jsonValue: any,options?:IJsonToHtmlOptions) : string
if (jsonValue['type'] === "style") {
delete attrsJson['style-text']
}
if(jsonValue['type'] === 'img'){
attrsJson['src'] = allattrs['url']
}
if(!(options?.customElementTypes && !isEmpty(options.customElementTypes) && options.customElementTypes[jsonValue['type']])) {
delete attrsJson['url']
}
Expand Down
4 changes: 2 additions & 2 deletions test/expectedJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1693,15 +1693,15 @@ export default {
<figure style="margin: auto; text-align: center;width: 204px;"><a href="https://app.contentstack.com/"><img asset_uid="bltfea8157ddfb8e776" src="https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg" /></a>
<figcaption style="text-align: center;" style="text-align: center;">Landscape</figcaption>
</figure>`,
"json": {"type":"doc","uid":"d712f7746e984559bbf591d689ef69f6","attrs":{},"children":[{"type":"p","attrs":{},"uid":"79d6defd99624ecc8302db0479330d72","children":[{"text":""}]},{"type":"reference","attrs":{"style":{"text-align":"center"},"redactor-attributes":{"asset_uid":"bltfea8157ddfb8e776","src":"https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg","position":"center","captionAttrs":{"style":"text-align: center;"},"caption":"Landscape","anchorLink":"https://app.contentstack.com/","asset-caption":"Landscape","width":204},"asset-name":"landscape-3.jpg","content-type-uid":"sys_assets","asset-link":"https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg","asset-type":"image/jpg","display-type":"display","type":"asset","asset-uid":"bltfea8157ddfb8e776","width":204,"position":"center","asset-caption":"Landscape"},"uid":"abc8e6a7f2974ad2a876356a6f4ae0fb","children":[{"text":""}]}]}
"json": {"type":"doc","uid":"d712f7746e984559bbf591d689ef69f6","attrs":{},"children":[{"type":"p","attrs":{},"uid":"79d6defd99624ecc8302db0479330d72","children":[{"text":""}]},{"type":"reference","attrs":{"style":{"text-align":"center"},"redactor-attributes":{"asset_uid":"bltfea8157ddfb8e776","src":"https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg","position":"center","captionAttrs":{"style":"text-align: center;"},"caption":"Landscape","anchorLink":"https://app.contentstack.com/","asset-caption":"Landscape","width":204},"link": "https://app.contentstack.com/","asset-name":"landscape-3.jpg","content-type-uid":"sys_assets","asset-link":"https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg","asset-type":"image/jpg","display-type":"display","type":"asset","asset-uid":"bltfea8157ddfb8e776","width":204,"position":"center","asset-caption":"Landscape"},"uid":"abc8e6a7f2974ad2a876356a6f4ae0fb","children":[{"text":""}]}]}
},
"anchor-reference-width-position-caption": {
"html":
`<p></p>
<figure style="margin: auto; text-align: center;width: 204px;"><a href="https://app.contentstack.com/"><img src="https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg" /></a>
<figcaption style="text-align: center;" style="text-align: center;">Landscape</figcaption>
</figure>`,
"json": {"type":"doc","uid":"d6cd7b938dcc41a8a75fb8bad29aa2e9","attrs":{},"children":[{"type":"p","attrs":{},"uid":"c17f2b982464422aaa58499b9525b437","children":[{"text":""}]},{"type":"img","attrs":{"style":{"text-align":"center"},"redactor-attributes":{"src":"https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg","position":"center","captionAttrs":{"style":"text-align: center;"},"caption":"Landscape","anchorLink":"https://app.contentstack.com/","width":204},"url":"https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg","width":204,"caption":"Landscape"},"uid":"929929b627704d38ae53ba6792ec8f69","children":[{"text":""}]}]}
"json": {"type":"doc","uid":"d6cd7b938dcc41a8a75fb8bad29aa2e9","attrs":{},"children":[{"type":"p","attrs":{},"uid":"c17f2b982464422aaa58499b9525b437","children":[{"text":""}]},{"type":"img","attrs":{"style":{"text-align":"center"},"redactor-attributes":{"src":"https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg","position":"center","captionAttrs":{"style":"text-align: center;"},"caption":"Landscape","anchorLink":"https://app.contentstack.com/","width":204},"url":"https://images.contentstack.io/v3/assets/blt858e12437ac2679e/bltfea8157ddfb8e776/6329f1106a7f7364973c028c/landscape-3.jpg","width":204,"caption":"Landscape","link":"https://app.contentstack.com/"},"children":[{"text":""}]}]}
},
"'\n' to <br>": {
"html": '<p>This is test for break element<br/>This is text on the next line.</p>',
Expand Down
56 changes: 53 additions & 3 deletions test/fromRedactor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { JSDOM } from "jsdom"
import isEqual from "lodash.isequal"
import omitdeep from "omit-deep-lodash"
import expectedValue from "./expectedJson"
import { IHtmlToJsonOptions } from "../src/types"

const docWrapper = (children: any) => {
return {
Expand Down Expand Up @@ -241,7 +242,7 @@ describe("Testing html to json conversion", () => {

test("should not convert stringify attrs when `allowNonStandardTags` is not true", () => {
const html = `<p><span from="Paul, Addy" to="[object Object]">Hi There!</span></p>`;
const json = {"attrs": {}, "children": [{"attrs": {}, "children": [{"attrs": {"redactor-attributes": {"from": "Paul, Addy", "to": "[object Object]"}, "style": {}}, "children": [{"attrs": {"style": {}}, "text": "Hi There!"}], "type": "span", "uid": "uid"}], "type": "p", "uid": "uid"}], "type": "doc", "uid": "uid"};
const json = {"attrs": {}, "children": [{"attrs": {}, "children": [{"attrs": {"redactor-attributes": {"from": "Paul, Addy", "to": "[object Object]"}, "style": {}}, "children": [{"text": "Hi There!"}], "type": "span", "uid": "uid"}], "type": "p", "uid": "uid"}], "type": "doc", "uid": "uid"};

const dom = new JSDOM(html);
let htmlDoc = dom.window.document.querySelector("body");
Expand All @@ -250,6 +251,50 @@ describe("Testing html to json conversion", () => {
});
})

describe("SPAN", () => {

test("should properly convert inline properties id and class to json", () => {
let html =`<p dir="ltr">Hello <span class="class" id="id">World</span></p>`
const json = htmlToJson(html)
expect(json).toStrictEqual({"type":"doc","uid":"uid","attrs":{},"children":[{"type":"p","attrs":{"style":{},"redactor-attributes":{"dir":"ltr"}},"uid":"uid","children":[{"text":"Hello "},{"text":"World","id":"id","classname":"class"}]}]})
})

test("should skip span if other element are inline and it does not have any attributes", () => {
let html =`<p dir="ltr">Hello <span>World</span></p>`
const json = htmlToJson(html)
expect(json).toStrictEqual({"type":"doc","uid":"uid","attrs":{},"children":[{"type":"p","attrs":{"style":{},"redactor-attributes":{"dir":"ltr"}},"uid":"uid","children":[{"text":"Hello "},{"text":"World"}]}]})
})

test("should not skip span if other element are inline and it does have any attribute", () => {
let html =`<p dir="ltr">Hello <span data-test="test">World</span></p>`
const json = htmlToJson(html)
expect(json).toStrictEqual({"type":"doc","uid":"uid","attrs":{},"children":[{"type":"p","attrs":{"style":{},"redactor-attributes":{"dir":"ltr"}},"uid":"uid","children":[{"text":"Hello "},{"type":"span","attrs":{"style":{},"redactor-attributes":{"data-test":"test"}},"uid":"uid","children":[{"text":"World"}]}]}]})
})

test("should consider the non standard elements as inline if it has attribute of inline with the span tag", () => {
let html = `<p><unknown inline="true"></unknown>Being an absolute <span>tropical</span> stunner</p>`
let jsonValue = htmlToJson(html, { allowNonStandardTags: true })
expect(jsonValue).toStrictEqual({"type":"doc","uid":"uid","attrs":{},"children":[{"type":"p","attrs":{},"uid":"uid","children":[{"type":"unknown","attrs":{"inline":"true"},"children":[{"text":""}]},{"text":"Being an absolute "},{"text":"tropical"},{"text":" stunner"}]}] })
})
})

test("should consider the non standard elements as inline if it has attribute of inline", () => {
let html = `<p><unknown inline="true"></unknown>Being an absolute <a href="https://chess.com">tropical</a> stunner</p>`
let jsonValue = htmlToJson(html, { allowNonStandardTags: true })
expect(jsonValue).toStrictEqual({"type":"doc","uid":"uid","attrs":{},"children":[{"type":"p","attrs":{},"uid":"uid","children":[{"type":"unknown","attrs":{"inline":"true"},"children":[{"text":""}]},{"text":"Being an absolute "},{"type":"a","attrs":{"url":"https://chess.com","style":{},"redactor-attributes":{"href":"https://chess.com"}},"uid":"uid","children":[{"text":"tropical"}]},{"text":" stunner"}]}] })
})


test("should convert asset to reference", () => {
const html = `<figure style="margin: 0; text-align: right">
<div style="display: inline-block"><a href="ss.com" target="_blank"><img src="https://picsum.photos/200" height="141" alt="image_(9).png" caption="ss" anchorLink="ss.com" class="embedded-asset" content-type-uid="sys_assets" type="asset" asset-alt="image_(9).png" width="148" max-height="141" max-width="148" style="max-height: 141px; height: 141px; text-align: right; max-width: 148px; width: auto" data-sys-asset-filelink="https://picsum.photos/200" data-sys-asset-uid="blt137d845621ef8168" data-sys-asset-filename="image_(9).png" data-sys-asset-contenttype="image/png" data-sys-asset-caption="ss" data-sys-asset-alt="image_(9).png" data-sys-asset-link="ss.com" data-sys-asset-position="right" data-sys-asset-isnewtab="true" sys-style-type="display" /></a>
<figcaption style="text-align:center">ss</figcaption>
</div>
</figure>
<p></p>`
const json = htmlToJson(html)
expect(json).toStrictEqual({"type":"doc","uid":"uid","attrs":{},"children":[{"type":"reference","attrs":{"style":{"text-align":"right"},"redactor-attributes":{"src":"https://picsum.photos/200","height":"141","alt":"image_(9).png","caption":"ss","type":"asset","asset-alt":"image_(9).png","max-height":"141","max-width":"148","sys-style-type":"display","position":"right","captionAttrs":{"style":"text-align:center"},"anchorLink":"ss.com","target":true,"asset-caption":"ss"},"class-name":"embedded-asset","width":148,"type":"asset","asset-caption":"ss","link":"ss.com","asset-alt":"image_(9).png","target":"_blank","position":"right","asset-link":"https://picsum.photos/200","asset-uid":"blt137d845621ef8168","display-type":"display","asset-name":"image_(9).png","asset-type":"image/png","content-type-uid":"sys_assets"},"uid":"uid","children":[{"text":""}]},{"type":"p","attrs":{},"uid":"uid","children":[{"text":""}]}] })
})
})


Expand Down Expand Up @@ -327,9 +372,14 @@ describe("CS-41001", () =>{
})
})

function htmlToJson (html, options) {




function htmlToJson (html: string, options: IHtmlToJsonOptions) {
const dom = new JSDOM(html);
let htmlDoc = dom.window.document.querySelector("body");
return fromRedactor(htmlDoc, options);

}
}

Loading

0 comments on commit 5cdf53f

Please sign in to comment.