5htp-core 0.5.1-3 → 0.5.1-4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "5htp-core",
|
|
3
3
|
"description": "Convenient TypeScript framework designed for Performance and Productivity.",
|
|
4
|
-
"version": "0.5.1-
|
|
4
|
+
"version": "0.5.1-4",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/5htp-core.git",
|
|
7
7
|
"license": "MIT",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
import { HeadingNode, HeadingTagType } from '@lexical/rich-text';
|
|
3
|
+
import { AutoLinkNode, LinkNode } from '@lexical/link';
|
|
4
|
+
|
|
5
|
+
export default class ReferenceLinkNode extends LinkNode {
|
|
6
|
+
|
|
7
|
+
public referenceTo?: string;
|
|
8
|
+
|
|
9
|
+
// Adding a static method to register the custom node
|
|
10
|
+
static getType() {
|
|
11
|
+
return 'reference-link';
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static clone(node) {
|
|
15
|
+
return new ReferenceLinkNode(node.__url, {
|
|
16
|
+
rel: node.__rel,
|
|
17
|
+
target: node.__target,
|
|
18
|
+
title: node.__title
|
|
19
|
+
}, node.__key);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Add a `referenceTo` attribute to the serialized JSON
|
|
23
|
+
static importJSON(serializedNode) {
|
|
24
|
+
const node = new ReferenceLinkNode(serializedNode.url);
|
|
25
|
+
node.referenceTo = serializedNode.referenceTo;
|
|
26
|
+
return node;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Ensure the `referenceTo` attribute is serialized in JSON
|
|
30
|
+
exportJSON() {
|
|
31
|
+
return {
|
|
32
|
+
...super.exportJSON(),
|
|
33
|
+
type: ReferenceLinkNode.getType(),
|
|
34
|
+
referenceTo: this.referenceTo
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Override createDOM to set the `referenceTo` attribute
|
|
39
|
+
createDOM(config) {
|
|
40
|
+
const dom = super.createDOM(config);
|
|
41
|
+
if (this.referenceTo) {
|
|
42
|
+
dom.setAttribute('class', this.referenceTo);
|
|
43
|
+
}
|
|
44
|
+
return dom;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Update the DOM to reflect changes in the `referenceTo` attribute
|
|
48
|
+
updateDOM(prevNode, dom, config) {
|
|
49
|
+
const updated = super.updateDOM(prevNode, dom, config);
|
|
50
|
+
if (this.referenceTo !== prevNode.referenceTo) {
|
|
51
|
+
dom.setAttribute('class', this.referenceTo);
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return updated;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -36,6 +36,7 @@ import { TweetNode } from '@client/components/inputv3/Rte/nodes/TweetNode';
|
|
|
36
36
|
import { YouTubeNode } from '@client/components/inputv3/Rte/nodes/YouTubeNode';
|
|
37
37
|
|
|
38
38
|
import HeadingWithAnchorNode from '@client/components/inputv3/Rte/nodes/HeadingNode';
|
|
39
|
+
import ReferenceLinkNode from '@client/components/inputv3/Rte/nodes/ReferenceLinkNode';
|
|
39
40
|
|
|
40
41
|
const PlaygroundNodes: Array<Klass<LexicalNode>> = [
|
|
41
42
|
/*HeadingNode, */HeadingWithAnchorNode,
|
|
@@ -74,6 +75,9 @@ const PlaygroundNodes: Array<Klass<LexicalNode>> = [
|
|
|
74
75
|
PageBreakNode,
|
|
75
76
|
LayoutContainerNode,
|
|
76
77
|
LayoutItemNode,
|
|
78
|
+
|
|
79
|
+
// Custom
|
|
80
|
+
ReferenceLinkNode
|
|
77
81
|
];
|
|
78
82
|
|
|
79
83
|
export default PlaygroundNodes;
|
package/src/server/utils/rte.ts
CHANGED
|
@@ -42,6 +42,15 @@ type LexicalNode = {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
type TRenderOptions = {
|
|
45
|
+
|
|
46
|
+
transform?: RteUtils["transformNode"],
|
|
47
|
+
|
|
48
|
+
render?: (
|
|
49
|
+
node: LexicalNode,
|
|
50
|
+
parent: LexicalNode | null,
|
|
51
|
+
options: TRenderOptions
|
|
52
|
+
) => Promise<LexicalNode>,
|
|
53
|
+
|
|
45
54
|
attachements?: {
|
|
46
55
|
disk: Driver,
|
|
47
56
|
directory: string,
|
|
@@ -103,8 +112,8 @@ export class RteUtils {
|
|
|
103
112
|
}
|
|
104
113
|
}
|
|
105
114
|
|
|
106
|
-
const root = await this.processContent(json.root, async (node) => {
|
|
107
|
-
return await this.transformNode(node, assets, options);
|
|
115
|
+
const root = await this.processContent(json.root, null, async (node, parent) => {
|
|
116
|
+
return await this.transformNode(node, parent, assets, options);
|
|
108
117
|
});
|
|
109
118
|
|
|
110
119
|
json = { ...json, root };
|
|
@@ -113,29 +122,30 @@ export class RteUtils {
|
|
|
113
122
|
const attachementOptions = options?.attachements;
|
|
114
123
|
if (attachementOptions && attachementOptions.prevVersion !== undefined) {
|
|
115
124
|
|
|
116
|
-
await this.processContent(root, async (node) => {
|
|
125
|
+
await this.processContent(root, null, async (node) => {
|
|
117
126
|
return await this.deleteUnusedFile(node, assets, attachementOptions);
|
|
118
127
|
});
|
|
119
128
|
}
|
|
120
129
|
|
|
121
130
|
// Convert json to HTML
|
|
122
|
-
const html = await this.jsonToHtml( json );
|
|
131
|
+
const html = await this.jsonToHtml( json, options );
|
|
123
132
|
|
|
124
133
|
return { html, json: content, ...assets };
|
|
125
134
|
}
|
|
126
135
|
|
|
127
136
|
private async processContent(
|
|
128
137
|
node: LexicalNode,
|
|
129
|
-
|
|
138
|
+
parent: LexicalNode | null,
|
|
139
|
+
callback: (node: LexicalNode, parent: LexicalNode | null) => Promise<LexicalNode>
|
|
130
140
|
) {
|
|
131
141
|
|
|
132
|
-
node = await callback(node);
|
|
142
|
+
node = await callback(node, parent);
|
|
133
143
|
|
|
134
144
|
// Recursion
|
|
135
145
|
if (node.children) {
|
|
136
146
|
for (let i = 0; i < node.children.length; i++) {
|
|
137
147
|
|
|
138
|
-
node.children[ i ] = await this.processContent( node.children[ i ], callback );
|
|
148
|
+
node.children[ i ] = await this.processContent( node.children[ i ], node, callback );
|
|
139
149
|
|
|
140
150
|
}
|
|
141
151
|
}
|
|
@@ -143,23 +153,34 @@ export class RteUtils {
|
|
|
143
153
|
return node;
|
|
144
154
|
}
|
|
145
155
|
|
|
146
|
-
private async transformNode(
|
|
156
|
+
private async transformNode(
|
|
157
|
+
node: LexicalNode,
|
|
158
|
+
parent: LexicalNode | null,
|
|
159
|
+
assets: TContentAssets,
|
|
160
|
+
options: TRenderOptions
|
|
161
|
+
): Promise<LexicalNode> {
|
|
147
162
|
|
|
148
|
-
//
|
|
163
|
+
// Images and files
|
|
149
164
|
if (node.type === 'image' || node.type === 'file') {
|
|
150
165
|
|
|
166
|
+
// Upload images and files and replace blobs by URLs
|
|
151
167
|
await this.processAttachement(
|
|
152
168
|
node as With<LexicalNode, 'src'>,
|
|
153
169
|
assets,
|
|
154
170
|
options,
|
|
155
171
|
);
|
|
156
172
|
|
|
173
|
+
// Headings
|
|
157
174
|
} else if (node.type === 'anchored-heading') {
|
|
158
175
|
|
|
176
|
+
// Create skeleton
|
|
159
177
|
await this.processHeading(node, assets);
|
|
160
178
|
|
|
161
179
|
}
|
|
162
180
|
|
|
181
|
+
if (options.transform)
|
|
182
|
+
node = await options.transform(node, parent, assets, options);
|
|
183
|
+
|
|
163
184
|
return node;
|
|
164
185
|
}
|
|
165
186
|
|
|
@@ -261,7 +282,17 @@ export class RteUtils {
|
|
|
261
282
|
return node;
|
|
262
283
|
}
|
|
263
284
|
|
|
264
|
-
public async jsonToHtml( json: LexicalState ) {
|
|
285
|
+
public async jsonToHtml( json: LexicalState, options: TRenderOptions = {} ) {
|
|
286
|
+
|
|
287
|
+
// Transform before rendering
|
|
288
|
+
const renderTransform = options.render;
|
|
289
|
+
if (renderTransform)
|
|
290
|
+
json = {
|
|
291
|
+
...json,
|
|
292
|
+
root: await this.processContent(json.root, null, async (node, parent) => {
|
|
293
|
+
return await renderTransform(node, parent, options);
|
|
294
|
+
})
|
|
295
|
+
}
|
|
265
296
|
|
|
266
297
|
// Server side: simulate DOM environment
|
|
267
298
|
const dom = new JSDOM(`<!DOCTYPE html><body></body>`);
|