Hi there,
I’m using the Get a single entry API to get the value from Rich Text to my application where I would like to have the values formatted as applied in the Rich Text of Contentful. Below is the response from the API:
I would like to know how to convert the response from Get a single entry API to html for the Rich Text values. Could someone help with this? Thanks!
Regards,
Diyab
If you are using javascript, you can use the @contentful/rich-text-html-renderer.
Hi Jaymie,
Thank you for the reply. I’m new to contentful, you mean this @contentful/rich-text-html-renderer - npm? I’m not using Javascript. Is there any API which passes the HTML in the json node or any other solution? Thanks!
No there isn’t (that I know of), but it’s actually not that hard to write something yourself.
Here is my code, I am sure you can convert it to whatever language you want:
import { DirectiveBinding } from "vue/types/options";
export const content = {
bind(el: HTMLElement, binding: DirectiveBinding): void {
const { value } = binding;
const openMarks = {
bold: true,
italic: true,
underline: true,
};
const html = parseHtmlString(value, openMarks);
el.innerHTML = html;
},
};
type nodeType =
| "document"
| "text"
| "paragraph"
| "hr"
| "unordered-list"
| "ordered-list"
| "hyperlink";
type mark = "bold" | "underline" | "italic";
interface Content {
nodeType: nodeType;
content: ContentItem[];
data: any;
}
interface OpenMark {
bold: boolean;
italic: boolean;
underline: boolean;
}
interface ContentItem extends Content {
marks: any[];
value: string;
}
function parseHtmlString(content: Content[], openMarks: OpenMark): string {
//console.log(JSON.parse(JSON.stringify(content)));
let htmlString = "";
content.forEach((item: Content) => {
//console.log(JSON.parse(JSON.stringify(item)));
switch (item.nodeType) {
case "hr":
htmlString += "<hr />";
break;
case "unordered-list":
htmlString += `<ul>${parseListItem(item.content, openMarks)}</ul>`;
break;
case "ordered-list":
htmlString += `<ol>${parseListItem(item.content, openMarks)}</ol>`;
break;
default:
htmlString += `<p>${parseChildren(item.content, openMarks)}</p>`;
break;
}
});
return htmlString;
}
function parseListItem(items: ContentItem[], openMarks: OpenMark): string {
return items
.map(
(item: ContentItem) =>
`<li>${parseHtmlString(item.content, openMarks)}</li>`
)
.join("");
}
function parseChildren(items: ContentItem[], openMarks: OpenMark): string {
return items
.map((item: ContentItem) => {
//console.log(console.log(JSON.parse(JSON.stringify(item))));
switch (item.nodeType) {
case "hyperlink":
return formatHyperlink(item);
default:
return formatMarks(item, openMarks);
}
})
.join("");
}
function formatMarks(item: ContentItem, openMarks: OpenMark): string {
//console.log(console.log(JSON.parse(JSON.stringify(item))));
let text = item.value?.trim();
if (!item?.marks?.length) return `${text} `;
const marks = item.marks.map((item: any) => item.type);
marks.forEach((mark: mark) => {
switch (mark) {
case "bold":
text = formatMark("strong", text, openMarks.bold);
if (!item.value) openMarks.bold = !openMarks.bold;
break;
case "italic":
text = formatMark("i", text, openMarks.italic);
if (!item.value) openMarks.italic = !openMarks.italic;
break;
case "underline":
text = formatMark("u", text, openMarks.underline);
if (!item.value) openMarks.underline = !openMarks.underline;
break;
}
});
return `${text} `;
}
function formatMark(mark: string, text: string, isOpen: boolean) {
if (text) return `<${mark}>${text}</${mark}>`;
return isOpen ? `<${mark}>` : `</${mark}>`;
}
function formatHyperlink(content: ContentItem) {
const email = isEmail(content.data.uri);
const text = content.content.find(
(content: any) => content.nodeType === "text"
);
if (email) {
return `<a href="${content.data.uri}" data-category="contact" data-action="email">${text.value}</a>`;
}
const outbound = isExternal(content.data.uri);
if (outbound) {
return `<a href="${content.data.uri}" data-category="navigate" data-action="outbound link">${text.value}</a>`;
} else {
return `<a href="${content.data.uri}" data-category="navigate" data-action="inbound link">${text.value}</a>`;
}
function isExternal(url: string): boolean {
const links = url.split("#");
const href = links[0] || ".";
return (
href.indexOf("http://") === 0 ||
href.indexOf("https://") === 0 ||
href.indexOf("www.") === 0
);
}
function isEmail(url: string): boolean {
return url.toLowerCase().indexOf("mailto") > -1;
}
}