Skip to content

Commit 82431aa

Browse files
committed
feat: 🚧 Json to HTML render
1 parent ba14335 commit 82431aa

File tree

11 files changed

+263
-59
lines changed

11 files changed

+263
-59
lines changed

src/Models/metadata-model.ts

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import StyleType from '../embedded-types/style-type';
2+
import TextNode from '../nodes/text';
3+
import { EmbeddedItem } from './embedded-object';
24
export interface Metadata {
35
text: string
4-
itemUid: string
5-
itemType: 'entry' | 'asset'
6-
styleType: StyleType
76
attributes: Attributes
7+
8+
itemUid: string | undefined
9+
itemType: 'entry' | 'asset' | undefined
10+
styleType: StyleType | undefined
811
contentTypeUid: string | undefined
12+
13+
item: EmbeddedItem | undefined
914
}
1015

1116
export interface Attributes {
12-
type: 'entry' | 'asset',
13-
class: string,
17+
type?: 'entry' | 'asset',
18+
class?: string,
1419
[key: string]: any,
15-
'sys-style-type': string,
20+
'sys-style-type'?: string,
1621
}
1722

1823
export interface EntryAttributes extends Attributes {
@@ -34,6 +39,19 @@ export function createMetadata(attribute: Attributes): Metadata {
3439
itemType: attribute.type,
3540
styleType: attribute["sys-style-type"] as StyleType,
3641
attributes: attribute,
37-
contentTypeUid: attribute["data-sys-content-type-uid"]
42+
contentTypeUid: attribute["data-sys-content-type-uid"],
43+
item: undefined
3844
}
45+
}
46+
47+
export function nodeToMetadata(attribute: Attributes, textNode: TextNode): Metadata {
48+
return {
49+
text: textNode.text,
50+
itemUid: attribute["entry-uid"] || attribute["asset-uid"],
51+
itemType: attribute.type,
52+
styleType: attribute["display-type"] as StyleType,
53+
attributes: attribute,
54+
contentTypeUid: attribute["content-type-uid"],
55+
item: undefined
56+
}
3957
}

src/helper/find-embeded-object.ts

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

@@ -46,32 +46,48 @@ export function findEmbeddedItems(object: Metadata, entry: EntryEmbedable): (Emb
4646

4747
export function findRenderString(
4848
metadata: Metadata,
49-
renderModel: EmbeddedItem,
5049
renderOptions?: RenderOption,
5150
): string {
52-
if ((!renderModel && renderModel === undefined) || (!metadata && metadata === undefined)) {
51+
if ((!metadata.item && metadata.item === undefined) || (!metadata && metadata === undefined)) {
5352
return '';
5453
}
5554

55+
if (!metadata.styleType) {
56+
return '';
57+
}
58+
59+
5660
if (renderOptions && renderOptions[metadata.styleType] !== undefined) {
57-
const renderFunction = renderOptions[metadata.styleType] as RenderNode;
61+
const renderFunction = renderOptions[metadata.styleType] as RenderItem;
5862

59-
if (
63+
if (
6064
(metadata.attributes as EntryAttributes)['data-sys-content-type-uid'] !== undefined &&
6165
typeof renderFunction !== 'function' &&
6266
renderFunction[(metadata.attributes as EntryAttributes)['data-sys-content-type-uid']] !== undefined
6367
) {
64-
return (renderFunction as RenderContentType)[(metadata.attributes as EntryAttributes)['data-sys-content-type-uid']]({item: renderModel, metadata});
68+
return (renderFunction as RenderContentType)[(metadata.attributes as EntryAttributes)['data-sys-content-type-uid']](metadata);
6569
} else if (
6670
(metadata.attributes as EntryAttributes)['data-sys-content-type-uid'] !== undefined &&
6771
typeof renderFunction !== 'function' &&
6872
(renderFunction as RenderContentType).$default !== undefined
6973
) {
70-
return (renderFunction as RenderContentType).$default({item: renderModel, metadata});
71-
} else if (typeof renderFunction === 'function') {
72-
return renderFunction({item: renderModel, metadata});
74+
return (renderFunction as RenderContentType).$default(metadata);
75+
} else if (
76+
metadata.contentTypeUid !== undefined &&
77+
typeof renderFunction !== 'function' &&
78+
renderFunction[metadata.contentTypeUid] !== undefined
79+
) {
80+
return (renderFunction as RenderContentType)[metadata.contentTypeUid](metadata)
81+
} else if (
82+
metadata.contentTypeUid !== undefined &&
83+
typeof renderFunction !== 'function' &&
84+
(renderFunction as RenderContentType).$default !== undefined
85+
) {
86+
return (renderFunction as RenderContentType).$default(metadata);
87+
} else if (typeof renderFunction === 'function') {
88+
return renderFunction(metadata);
7389
}
7490
}
75-
const defaultRenderFunction = defaultOptions[metadata.styleType] as RenderNode;
76-
return defaultRenderFunction({item: renderModel, metadata});
91+
const defaultRenderFunction = defaultOptions[metadata.styleType] as RenderItem;
92+
return defaultRenderFunction(metadata);
7793
}

src/json-to-html.ts

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
1-
import { RenderOption } from './options';
1+
import Node from './nodes/node';
2+
import TextNode from './nodes/text';
3+
import Document from './nodes/document';
4+
import MarkType from './nodes/mark-type';
5+
import { nodeToMetadata } from './Models/metadata-model';
26
import { EntryEmbedable } from './Models/embedded-object';
37
import { findRenderContent } from './helper/find-render-content';
4-
import Document from './nodes/document';
5-
import { defaultOptions } from './options/default-options';
8+
import { defaultNodeOption } from './options/default-node-options';
9+
import { Next, RenderMark, RenderNode, RenderOption } from './options';
10+
import { findEmbeddedItems, findRenderString } from './helper/find-embeded-object';
611

7-
export const defaultNodeOption: RenderOption = {
8-
9-
}
12+
export type AnyNode = TextNode | Node;
1013

1114
export function jsonToHTML(option: {
1215
entry: EntryEmbedable| EntryEmbedable[],
@@ -65,21 +68,69 @@ function enumerateContents(
6568
})
6669
return result
6770
}
68-
return parseJsonToHTML(content)
71+
const commonRenderOption = {
72+
...defaultNodeOption,
73+
...renderOption
74+
}
75+
return nodeChildrenToHTML(content.children, commonRenderOption, entry)
6976
}
7077

71-
export function parseJsonToHTML(
72-
content: Document,
73-
entry?: EntryEmbedable,
74-
renderOption?: RenderOption,
78+
export function textNodeToHTML(node: TextNode, renderOption: RenderOption): string {
79+
let text = node.text
80+
if (node.superscript) {
81+
text = (renderOption[MarkType.SUPERSCRIPT] as RenderMark)(text)
82+
}
83+
if (node.subscript) {
84+
text = (renderOption[MarkType.SUBSCRIPT] as RenderMark)(text)
85+
}
86+
if (node.inlineCode) {
87+
text = (renderOption[MarkType.INLINE_CODE] as RenderMark)(text)
88+
}
89+
if (node.strikethrough) {
90+
text = (renderOption[MarkType.STRIKE_THROUGH] as RenderMark)(text)
91+
}
92+
if (node.underline) {
93+
text = (renderOption[MarkType.UNDERLINE] as RenderMark)(text)
94+
}
95+
if (node.italic) {
96+
text = (renderOption[MarkType.ITALIC] as RenderMark)(text)
97+
}
98+
if (node.bold) {
99+
text = (renderOption[MarkType.BOLD] as RenderMark)(text)
100+
}
101+
return text
102+
}
103+
104+
export function referenceToHTML(node: Node,
105+
renderOption: RenderOption,
106+
entry?: EntryEmbedable
75107
): string {
76-
// TODO: functionality to be added
77-
const renderNode = {
78-
...defaultNodeOption,
79-
...defaultOptions,
80-
...renderOption
108+
if (!entry) {
109+
return ''
81110
}
111+
const metadata = nodeToMetadata(node.attrs, node.children.length > 0 ? node.children[0] as unknown as TextNode : undefined)
112+
metadata.item = findEmbeddedItems(metadata, entry)[0]
113+
return findRenderString(metadata, renderOption)
114+
}
115+
116+
function nodeChildrenToHTML(nodes: AnyNode[],
117+
renderOption: RenderOption,
118+
entry?: EntryEmbedable,
119+
): string {
120+
return nodes.map<string>((node: AnyNode) => nodeToHTML(node, renderOption, entry)).join('')
121+
}
82122

83-
84-
return ''
123+
function nodeToHTML(
124+
node: AnyNode,
125+
renderOption: RenderOption,
126+
entry?: EntryEmbedable,
127+
): string {
128+
if (!node.type) {
129+
return textNodeToHTML(node as TextNode, renderOption)
130+
}else if ((node.type as string) === 'reference') {
131+
return referenceToHTML(node, renderOption, entry)
132+
}else {
133+
const next: Next = nodes => nodeChildrenToHTML(nodes, renderOption, entry)
134+
return (renderOption[node.type] as RenderNode)(node, next)
135+
}
85136
}

src/nodes/document.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,9 @@ import NodeType from "./node-type"
33

44
export default class Document extends Node {
55
type: NodeType.DOCUMENT
6+
7+
constructor() {
8+
super()
9+
this.type = NodeType.DOCUMENT
10+
}
611
}

src/nodes/mark-type.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ enum MarkType {
33
ITALIC = 'italic',
44
UNDERLINE = 'underline',
55

6-
STRIKETHROUGH = 'strikethrough',
7-
INLINECODE = 'inlineCode',
6+
STRIKE_THROUGH = 'strikethrough',
7+
INLINE_CODE = 'inlineCode',
88

99

1010
SUBSCRIPT = 'subscript',
1111
SUPERSCRIPT = 'superscript'
12-
}
12+
}
13+
14+
export default MarkType

src/nodes/node-type.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
enum NodeType {
22
DOCUMENT = 'doc',
33
PARAGRAPH = 'p',
4+
45
LINK = 'a',
6+
IMAGE = 'img',
7+
EMBED = 'embed',
58

69
HEADING_1 = 'h1',
710
HEADING_2 = 'h2',
@@ -27,7 +30,7 @@ enum NodeType {
2730
BLOCK_QUOTE = 'blockquote',
2831
CODE = 'code',
2932

30-
REFERENCE = 'reference',
33+
TEXT = 'text'
3134
}
3235

3336
export default NodeType;

src/nodes/text.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { Node } from "./node"
2-
import NodeType from "./node-type"
1+
import Node from "./node"
32

4-
export default class TextNode {
3+
export default class TextNode extends Node {
54
bold?: boolean
65
italic?: boolean
76
underline?: boolean
@@ -11,4 +10,9 @@ export default class TextNode {
1110
subscript?: boolean
1211

1312
text: string
13+
14+
constructor(text: string) {
15+
super()
16+
this.text = text
17+
}
1418
}

0 commit comments

Comments
 (0)