Skip to content

Commit 691d989

Browse files
authored
Merge pull request #10 from contentstack/feature/supercharged-rte
Feature/supercharged rte
2 parents 52ce41b + c083eaf commit 691d989

File tree

9 files changed

+225
-133
lines changed

9 files changed

+225
-133
lines changed

src/Models/embedded-object.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export interface EmbeddedItem {
22
uid: string;
3-
_content_type_uid: string;
3+
_content_type_uid?: string;
44
[propName: string]: any;
55
}
66

src/Models/json-rte-model.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Document from "../nodes/document";
2+
export interface JsonRTE {
3+
json: Document| Document[],
4+
embedded_itemsConnection?: EmbeddedConnection
5+
}
6+
7+
export interface EmbeddedConnection {
8+
edges: {
9+
node: EntryNode;
10+
}[]
11+
}
12+
13+
export interface EntryNode {
14+
system: SystemField;
15+
[propName: string]: any;
16+
}
17+
export interface SystemField {
18+
uid: string;
19+
content_type_uid?: string;
20+
[propName: string]: any;
21+
}

src/gql.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import Node from './nodes/node';
2+
import TextNode from './nodes/text';
3+
import { RenderOption } from './options';
4+
import { JsonRTE } from './Models/json-rte-model';
5+
import { Metadata } from './Models/metadata-model';
6+
import { findRenderContent } from './helper/find-render-content';
7+
import { findGQLEmbeddedItems } from './helper/find-embeded-object';
8+
import { EmbeddedItem, EntryEmbedable } from './Models/embedded-object';
9+
import { enumerate, enumerateContents } from './helper/enumerate-entries';
10+
11+
export type AnyNode = TextNode | Node;
12+
13+
function jsonToHTML(option: {
14+
entry: EmbeddedItem| EmbeddedItem[],
15+
paths: string[],
16+
renderOption?: RenderOption,
17+
}) {
18+
if (option.entry instanceof Array) {
19+
enumerate(option.entry, (entry: EmbeddedItem) => {
20+
jsonToHTML({entry, paths: option.paths, renderOption: option.renderOption})
21+
})
22+
} else {
23+
enumerateKeys({
24+
entry: option.entry,
25+
paths: option.paths,
26+
renderOption: option.renderOption,
27+
})
28+
}
29+
}
30+
31+
function enumerateKeys(option: {
32+
entry: EntryEmbedable,
33+
paths: string[],
34+
renderOption?: RenderOption,
35+
}) {
36+
for (const key of option.paths) {
37+
findRenderContent(key,
38+
option.entry as EntryEmbedable,
39+
((content: JsonRTE) => {
40+
if (content && content.json) {
41+
const edges = content.embedded_itemsConnection ? content.embedded_itemsConnection.edges : []
42+
const items = Object.values(edges || []).reduce((accumulator, value) => accumulator.concat(value.node), [])
43+
return enumerateContents(content.json, option.renderOption, (metadata: Metadata) => {
44+
return findGQLEmbeddedItems(metadata, items)[0]
45+
})
46+
}
47+
return content as unknown as string
48+
}))
49+
}
50+
}
51+
export const GQL = {
52+
jsonToHTML
53+
}

src/helper/enumerate-entries.ts

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { AnyNode } from "../json-to-html";
2+
import { EmbeddedItem, EntryEmbedable } from "../Models/embedded-object";
3+
import { Metadata, nodeToMetadata } from "../Models/metadata-model";
4+
import MarkType from "../nodes/mark-type";
5+
import TextNode from "../nodes/text";
6+
import Node from '../nodes/node'
7+
import Document from '../nodes/document'
8+
import { Next, RenderMark, RenderNode, RenderOption } from "../options";
9+
import { defaultNodeOption } from "../options/default-node-options";
10+
import { findRenderString } from "./find-embeded-object";
11+
import { EntryNode } from "../Models/json-rte-model";
12+
13+
export function enumerate(
14+
entries: EntryEmbedable[] | EmbeddedItem[],
15+
process: (entry: EntryEmbedable| EmbeddedItem) => void
16+
) {
17+
for (const entry of entries) {
18+
process(entry)
19+
}
20+
}
21+
22+
export function enumerateContents(
23+
content:Document | Document[],
24+
renderOption?: RenderOption,
25+
renderEmbed?: (metadata: Metadata) => EmbeddedItem| EntryNode
26+
): string | string[] {
27+
if (!(content instanceof Array) && content.type !== 'doc') {
28+
return content as unknown as string
29+
}
30+
if (content instanceof Array) {
31+
const result: string[] = []
32+
content.forEach((doc) => {
33+
result.push(enumerateContents(doc, renderOption, renderEmbed) as string)
34+
})
35+
return result
36+
}
37+
const commonRenderOption = {
38+
...defaultNodeOption,
39+
...renderOption
40+
}
41+
return nodeChildrenToHTML(content.children, commonRenderOption, renderEmbed)
42+
}
43+
44+
export function textNodeToHTML(node: TextNode, renderOption: RenderOption): string {
45+
let text = node.text
46+
if (node.superscript) {
47+
text = (renderOption[MarkType.SUPERSCRIPT] as RenderMark)(text)
48+
}
49+
if (node.subscript) {
50+
text = (renderOption[MarkType.SUBSCRIPT] as RenderMark)(text)
51+
}
52+
if (node.inlineCode) {
53+
text = (renderOption[MarkType.INLINE_CODE] as RenderMark)(text)
54+
}
55+
if (node.strikethrough) {
56+
text = (renderOption[MarkType.STRIKE_THROUGH] as RenderMark)(text)
57+
}
58+
if (node.underline) {
59+
text = (renderOption[MarkType.UNDERLINE] as RenderMark)(text)
60+
}
61+
if (node.italic) {
62+
text = (renderOption[MarkType.ITALIC] as RenderMark)(text)
63+
}
64+
if (node.bold) {
65+
text = (renderOption[MarkType.BOLD] as RenderMark)(text)
66+
}
67+
return text
68+
}
69+
export function referenceToHTML(node: Node,
70+
renderOption: RenderOption,
71+
renderEmbed?: (metadata: Metadata) => EmbeddedItem | EntryNode
72+
): string {
73+
if (!renderEmbed) {
74+
return ''
75+
}
76+
const metadata = nodeToMetadata(node.attrs, ((node.children && node.children.length > 0) ? node.children[0]: {}) as unknown as TextNode)
77+
const item = renderEmbed(metadata)
78+
return findRenderString(item, metadata, renderOption)
79+
}
80+
81+
function nodeChildrenToHTML(nodes: AnyNode[],
82+
renderOption: RenderOption,
83+
renderEmbed?: (metadata: Metadata) => EmbeddedItem | EntryNode,
84+
): string {
85+
return nodes.map<string>((node: AnyNode) => nodeToHTML(node, renderOption, renderEmbed)).join('')
86+
}
87+
88+
function nodeToHTML(
89+
node: AnyNode,
90+
renderOption: RenderOption,
91+
renderEmbed?: (metadata: Metadata) => EmbeddedItem | EntryNode,
92+
): string {
93+
if (!node.type) {
94+
return textNodeToHTML(node as TextNode, renderOption)
95+
}else if ((node.type as string) === 'reference') {
96+
return referenceToHTML(node, renderOption, renderEmbed)
97+
}else {
98+
const next: Next = nodes => nodeChildrenToHTML(nodes, renderOption, renderEmbed)
99+
return (renderOption[node.type] as RenderNode)(node, next)
100+
}
101+
}

src/helper/find-embeded-object.ts

Lines changed: 28 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,58 @@
11
import { EntryEmbedable, EmbeddedItem } from '../Models/embedded-object';
2-
import { RenderOption, RenderNode, RenderContentType, RenderItem } from '../options/index';
2+
import { RenderOption, RenderContentType, RenderItem } from '../options/index';
33
import { EntryAttributes, Metadata } from '../Models/metadata-model';
44
import { defaultOptions } from '../options/default-options';
5+
import { EntryNode } from '../Models/json-rte-model';
56

67
// This function will find Embedded object present in string
78
export function findEmbeddedEntry(
89
uid: string,
910
contentTypeUid: string,
10-
embeddeditems: EmbeddedItem[] = [],
11-
): EmbeddedItem[] {
12-
return embeddeditems.filter((entry) => {
13-
if (entry.uid === uid && entry._content_type_uid === contentTypeUid) {
11+
embeddeditems: (EmbeddedItem| EntryNode)[] = [],
12+
): (EmbeddedItem | EntryNode)[] {
13+
return embeddeditems.filter((entry: any) => {
14+
if ((entry.uid && (entry as EmbeddedItem).uid === uid && (entry as EmbeddedItem)._content_type_uid === contentTypeUid)|| (entry.system && (entry as EntryNode).system.uid === uid && (entry as EntryNode).system.content_type_uid === contentTypeUid)) {
1415
return entry;
1516
}
1617
});
1718
}
1819

19-
export function findEmbeddedAsset(uid: string, embeddedAssets: EmbeddedItem[] = []): EmbeddedItem[] {
20-
return embeddedAssets.filter((asset) => {
21-
if (asset.uid === uid) {
20+
export function findEmbeddedAsset(uid: string, embeddedAssets: (EmbeddedItem| EntryNode)[] = []): (EmbeddedItem| EntryNode)[] {
21+
return embeddedAssets.filter((asset: any) => {
22+
if ((asset.uid && (asset as EmbeddedItem).uid === uid) || asset.system && (asset as EntryNode).system.uid === uid) {
2223
return asset;
2324
}
2425
});
2526
}
2627

27-
export function findEmbeddedItems(object: Metadata, entry: EntryEmbedable): (EmbeddedItem)[] {
28+
export function findGQLEmbeddedItems(metadata: Metadata, items: (EmbeddedItem| EntryNode)[]): (EmbeddedItem| EntryNode)[] {
29+
if (metadata.itemType === 'entry') {
30+
return findEmbeddedEntry(
31+
metadata.itemUid,
32+
metadata.contentTypeUid,
33+
items
34+
);
35+
} else {
36+
return findEmbeddedAsset(
37+
metadata.itemUid,
38+
items
39+
);
40+
}
41+
}
42+
43+
export function findEmbeddedItems(object: Metadata, entry: EntryEmbedable): (EmbeddedItem| EntryNode)[] {
2844
if (object && object !== undefined && entry && entry !== undefined) {
2945
if (entry._embedded_items !== undefined) {
3046
const entryEmbedable = entry
31-
if (object.itemType === 'entry') {
32-
return findEmbeddedEntry(
33-
object.itemUid,
34-
object.contentTypeUid,
35-
Object.values(entryEmbedable._embedded_items || []).reduce((accumulator, value) => accumulator.concat(value), []),
36-
);
37-
} else {
38-
return findEmbeddedAsset(
39-
object.itemUid,
40-
Object.values(entryEmbedable._embedded_items|| []).reduce((accumulator, value) => accumulator.concat(value), []),);
41-
}
47+
const items = Object.values(entryEmbedable._embedded_items || []).reduce((accumulator, value) => accumulator.concat(value), [])
48+
return findGQLEmbeddedItems(object, items)
4249
}
4350
}
4451
return [];
4552
}
4653

4754
export function findRenderString(
48-
item: EmbeddedItem,
55+
item: EmbeddedItem | EntryNode,
4956
metadata: Metadata,
5057
renderOptions?: RenderOption,
5158
): string {

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
2-
31
export { Next, Option, RenderNode, RenderMark, RenderItem, RenderContentType, RenderOption } from './options/index';
42
export { EntryEmbedable, EmbeddedItem as EntryModel } from './Models/embedded-object';
53
export { Metadata, Attributes, attributeToString } from './Models/metadata-model';
64
export { default as StyleType } from './embedded-types/style-type';
75
export { render, renderContent } from './render-embedded-objects';
6+
export { EntryNode, JsonRTE } from './Models/json-rte-model';
87

98
export { default as NodeType } from './nodes/node-type'
109
export { default as MarkType } from './nodes/mark-type'
1110
export { default as Node} from './nodes/node'
1211
export { default as Document } from './nodes/document'
1312
export { default as TextNode } from './nodes/text';
1413
export { jsonToHTML } from './json-to-html'
14+
export { GQL } from './gql'

0 commit comments

Comments
 (0)