Skip to content

Commit 1c7a514

Browse files
authored
merge: Use new rendering logic. Bug fixes.
refactor: Refactor to use new rendering logic, fix a series of issues caused by modified msg HTML format.
2 parents 504e67f + c17df3a commit 1c7a514

23 files changed

+1225
-654
lines changed

diagram/frag_processor.drawio

+45-62
Large diffs are not rendered by default.

diagram/frag_processor_2.3.5.drawio

+134
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
<mxfile host="Electron" modified="2024-07-09T07:32:55.857Z" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/21.6.1 Chrome/112.0.5615.204 Electron/24.6.1 Safari/537.36" etag="cP2pwXDnCcL_vyiy6X7w" version="21.6.1" type="device">
2+
<diagram name="Page-1" id="zotAlQJJTCq7FzbI9wUf">
3+
<mxGraphModel dx="1295" dy="519" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="3300" pageHeight="4681" math="0" shadow="0">
4+
<root>
5+
<mxCell id="0" />
6+
<mxCell id="1" parent="0" />
7+
<mxCell id="8dtW_6vD572V2-CuLths-22" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
8+
<mxGeometry x="395" y="240" width="130" height="260" as="geometry" />
9+
</mxCell>
10+
<mxCell id="8dtW_6vD572V2-CuLths-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="8dtW_6vD572V2-CuLths-20" target="8dtW_6vD572V2-CuLths-28">
11+
<mxGeometry relative="1" as="geometry" />
12+
</mxCell>
13+
<mxCell id="8dtW_6vD572V2-CuLths-20" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" vertex="1" parent="1">
14+
<mxGeometry x="580" y="240" width="200" height="260" as="geometry" />
15+
</mxCell>
16+
<mxCell id="8dtW_6vD572V2-CuLths-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="8dtW_6vD572V2-CuLths-1">
17+
<mxGeometry relative="1" as="geometry">
18+
<mxPoint x="400" y="365" as="targetPoint" />
19+
</mxGeometry>
20+
</mxCell>
21+
<mxCell id="8dtW_6vD572V2-CuLths-1" value="MsgBox" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
22+
<mxGeometry x="280" y="291.25" width="80" height="147.5" as="geometry" />
23+
</mxCell>
24+
<mxCell id="8dtW_6vD572V2-CuLths-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="8dtW_6vD572V2-CuLths-2" target="8dtW_6vD572V2-CuLths-11">
25+
<mxGeometry relative="1" as="geometry" />
26+
</mxCell>
27+
<mxCell id="8dtW_6vD572V2-CuLths-2" value="SPAN text" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
28+
<mxGeometry x="420" y="265" width="80" height="40" as="geometry" />
29+
</mxCell>
30+
<mxCell id="8dtW_6vD572V2-CuLths-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="8dtW_6vD572V2-CuLths-3" target="8dtW_6vD572V2-CuLths-11">
31+
<mxGeometry relative="1" as="geometry">
32+
<Array as="points">
33+
<mxPoint x="550" y="335" />
34+
<mxPoint x="550" y="285" />
35+
</Array>
36+
</mxGeometry>
37+
</mxCell>
38+
<mxCell id="8dtW_6vD572V2-CuLths-3" value="SPAN text" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
39+
<mxGeometry x="420" y="315" width="80" height="40" as="geometry" />
40+
</mxCell>
41+
<mxCell id="8dtW_6vD572V2-CuLths-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="8dtW_6vD572V2-CuLths-4" target="8dtW_6vD572V2-CuLths-12">
42+
<mxGeometry relative="1" as="geometry">
43+
<Array as="points">
44+
<mxPoint x="570" y="385" />
45+
<mxPoint x="570" y="335" />
46+
</Array>
47+
</mxGeometry>
48+
</mxCell>
49+
<mxCell id="8dtW_6vD572V2-CuLths-4" value="SPAN other" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
50+
<mxGeometry x="420" y="365" width="80" height="40" as="geometry" />
51+
</mxCell>
52+
<mxCell id="8dtW_6vD572V2-CuLths-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#f5f5f5;strokeColor=#666666;dashed=1;" edge="1" parent="1" source="8dtW_6vD572V2-CuLths-5" target="8dtW_6vD572V2-CuLths-18">
53+
<mxGeometry relative="1" as="geometry" />
54+
</mxCell>
55+
<mxCell id="8dtW_6vD572V2-CuLths-5" value="DIV other" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
56+
<mxGeometry x="420" y="415" width="80" height="40" as="geometry" />
57+
</mxCell>
58+
<mxCell id="8dtW_6vD572V2-CuLths-9" value="Pieces" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
59+
<mxGeometry x="430" y="465" width="60" height="30" as="geometry" />
60+
</mxCell>
61+
<mxCell id="8dtW_6vD572V2-CuLths-11" value="textSpanProcessor" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
62+
<mxGeometry x="600" y="265" width="160" height="40" as="geometry" />
63+
</mxCell>
64+
<mxCell id="8dtW_6vD572V2-CuLths-12" value="spanReplaceProcessor" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
65+
<mxGeometry x="600" y="315" width="160" height="40" as="geometry" />
66+
</mxCell>
67+
<mxCell id="8dtW_6vD572V2-CuLths-13" value="..." style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
68+
<mxGeometry x="600" y="365" width="160" height="40" as="geometry" />
69+
</mxCell>
70+
<mxCell id="8dtW_6vD572V2-CuLths-18" value="Ignored" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#f5f5f5;fontColor=#333333;strokeColor=#666666;" vertex="1" parent="1">
71+
<mxGeometry x="600" y="415" width="160" height="40" as="geometry" />
72+
</mxCell>
73+
<mxCell id="8dtW_6vD572V2-CuLths-21" value="FragProcessor" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
74+
<mxGeometry x="630" y="460" width="100" height="40" as="geometry" />
75+
</mxCell>
76+
<mxCell id="8dtW_6vD572V2-CuLths-28" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
77+
<mxGeometry x="830" y="240" width="190" height="260" as="geometry" />
78+
</mxCell>
79+
<mxCell id="8dtW_6vD572V2-CuLths-23" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
80+
<mxGeometry x="856.63" y="265" width="133.37" height="40" as="geometry" />
81+
</mxCell>
82+
<mxCell id="8dtW_6vD572V2-CuLths-24" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
83+
<mxGeometry x="856.63" y="315" width="133.37" height="40" as="geometry" />
84+
</mxCell>
85+
<mxCell id="8dtW_6vD572V2-CuLths-25" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
86+
<mxGeometry x="856.63" y="365" width="133.37" height="40" as="geometry" />
87+
</mxCell>
88+
<mxCell id="8dtW_6vD572V2-CuLths-27" value="..." style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
89+
<mxGeometry x="856.63" y="415" width="133.37" height="40" as="geometry" />
90+
</mxCell>
91+
<mxCell id="8dtW_6vD572V2-CuLths-38" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="8dtW_6vD572V2-CuLths-32" target="8dtW_6vD572V2-CuLths-37">
92+
<mxGeometry relative="1" as="geometry" />
93+
</mxCell>
94+
<mxCell id="8dtW_6vD572V2-CuLths-39" value="Accumulate&lt;br&gt;`mark`" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="8dtW_6vD572V2-CuLths-38">
95+
<mxGeometry x="0.0165" y="1" relative="1" as="geometry">
96+
<mxPoint x="-1" y="1" as="offset" />
97+
</mxGeometry>
98+
</mxCell>
99+
<mxCell id="8dtW_6vD572V2-CuLths-32" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
100+
<mxGeometry x="280" y="600" width="190" height="260" as="geometry" />
101+
</mxCell>
102+
<mxCell id="8dtW_6vD572V2-CuLths-33" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
103+
<mxGeometry x="306.63" y="630" width="133.37" height="40" as="geometry" />
104+
</mxCell>
105+
<mxCell id="8dtW_6vD572V2-CuLths-34" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
106+
<mxGeometry x="306.63" y="681.25" width="133.37" height="40" as="geometry" />
107+
</mxCell>
108+
<mxCell id="8dtW_6vD572V2-CuLths-35" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
109+
<mxGeometry x="306.63" y="735" width="133.37" height="40" as="geometry" />
110+
</mxCell>
111+
<mxCell id="8dtW_6vD572V2-CuLths-36" value="..." style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
112+
<mxGeometry x="306.63" y="790" width="133.37" height="40" as="geometry" />
113+
</mxCell>
114+
<mxCell id="8dtW_6vD572V2-CuLths-42" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="8dtW_6vD572V2-CuLths-37" target="8dtW_6vD572V2-CuLths-40">
115+
<mxGeometry relative="1" as="geometry" />
116+
</mxCell>
117+
<mxCell id="8dtW_6vD572V2-CuLths-43" value="Rendered&lt;br&gt;HTML" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="8dtW_6vD572V2-CuLths-42">
118+
<mxGeometry x="-0.2279" relative="1" as="geometry">
119+
<mxPoint x="9" as="offset" />
120+
</mxGeometry>
121+
</mxCell>
122+
<mxCell id="8dtW_6vD572V2-CuLths-37" value="Markdown It Renderer" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
123+
<mxGeometry x="580" y="700" width="170" height="60" as="geometry" />
124+
</mxCell>
125+
<mxCell id="8dtW_6vD572V2-CuLths-40" value="Replacer&lt;br&gt;&lt;i&gt;`pieceInfoList[i].replace()`&lt;/i&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
126+
<mxGeometry x="856.63" y="700" width="170" height="60" as="geometry" />
127+
</mxCell>
128+
<mxCell id="8dtW_6vD572V2-CuLths-41" value="pieceInfoList" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" vertex="1" parent="1">
129+
<mxGeometry x="873.3099999999998" y="460" width="100" height="40" as="geometry" />
130+
</mxCell>
131+
</root>
132+
</mxGraphModel>
133+
</diagram>
134+
</mxfile>

docs/dev/msg_rendering_process.md

+59-27
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,90 @@
11
- [Workflow](#workflow)
2-
- [MsgProcessInfo](#msgprocessinfo)
3-
- [FragmentProcessFunc](#fragmentprocessfunc)
2+
- [Fragments](#fragments)
3+
- [Fragment Processor](#fragment-processor)
4+
- [Children Replacement](#children-replacement)
5+
- [Rendered Flag](#rendered-flag)
6+
- [Global \& MessageRendered Callback](#global--messagerendered-callback)
47
- [Refs](#refs)
58

69

710
# Workflow
811

9-
Currently the plugin does NOT rendering all content inside a message box. We only deal with contents that may need go through the markdown renderer. Also, since some element should NOT be considered as Markdown when rendering and should keep what it look like throughout the rendering, we introduced the *Replacer*.
12+
Currently the plugin does NOT rendering all content inside a message box. We only deal with contents that may need go through the markdown renderer. Also, since some element should NOT be considered as Markdown when rendering and should keep what it look like throughout the rendering, we introduced the concept of **Fragement Processor**(FragProcessor).
1013

11-
![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/c5f986c4-5bb5-410f-8366-c1cffd6c2c3e)
14+
## Fragments
1215

13-
As you see, we consider the `childern` of the message box as pieces. Then we have a list of `FragProcessor` which take in charge of convert the list of HTML children (or you can say: list of pieces) into list of `MsgProcessInfo` object.
16+
As you see, we **consider the `childern` of the message box as a "fragment"**. Then we have **a list of `FragProcessor`, each takes in charge of render a certain type of fragments**.
1417

15-
## MsgProcessInfo
18+
## Fragment Processor
1619

17-
This refers to object like: `{mark:..., replace:...}`:
20+
Definition:
1821

19-
- `mark` Determine how it looks like for Markdown Renderer.
20-
- `replace` Determine replace behaviour after markdown render process.
22+
```typescript
23+
type FragmentProcessFunc = (
24+
parent: HTMLElement,
25+
element: HTMLElement,
26+
index: number,
27+
) => FragmentProcessFuncRetType | undefined;
28+
```
2129

22-
This decide what this element looks like when passed to Markdown Renderer. For example, an element `<span>123</span>` should converted to:
30+
When `render()` function is triggered, a provided list of Fragment Processor will be iterated from begin to end **respectively and preemptively**.
2331

24-
```js
25-
{mark: '123', replace: undefined}
26-
```
32+
This means, for a single fragment, once a processor successfully returned a not `undefined` value *(actually it should be `FragmentProcessFuncRetType` obejct)*, the loop is end and the return value is used for this fragment.
2733

28-
And an element that should be replaced later `<img class="face-element__icon"></img>` could be converted to:
34+
![Fragment Processor](https://github.com/user-attachments/assets/670dd3f2-7660-4a59-99bb-9e985f19d323)
2935

30-
```js
31-
{
32-
mark: '<span id="some_placeholder"></span>',
33-
replace: (parent)=>{...}
36+
## Children Replacement
37+
38+
Let's look into the return type of `FragmentProcessFunc`:
39+
40+
```typescript
41+
interface FragmentProcessFuncRetType {
42+
original: HTMLElement;
43+
rendered: HTMLElement;
3444
}
3545
```
3646

37-
## FragmentProcessFunc
47+
As you see, it specified the `original` SPAN element, and a new `rendered` element. For now, we just replace the `original` child of `messageBox` with `rendered`.
3848

39-
The work of generating `MsgProcessInfo` based on HTML pieces is done by a set of function with type `FragmentProcessFunc`.
49+
> **Notice**
50+
>
51+
> Keep in mind that the `original` HTML element passed to Fragment Processor could be directly updated.
52+
>
53+
> In some cases, Fragment Processor function may directly mutated the `original` HTML element due to performance or other consideration. In this case, `original===rendered` should be true in the returned `FragmentProcessFuncRetType`.
4054
41-
There is a list of `FragmentProcessFunc`. When iterating pieces, all `FragmentProcessFunc` inside the list will be **triggered from begin to end respectively and preemptively**, which means once a processor successfully returned a `MsgProcessInfo` object, process interrupt and program will continue with next piece.
55+
# Rendered Flag
4256

43-
-----
57+
We use a special HTML `class` text to mark a message box as `rendered` in `renderSingleMsgBox()` function. When `render()` triggered, it first detect all message box inside UI, then filter the ones that already been rendered. This approach could not only improve the performance but also solve some async issue.
4458

45-
![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/04247260-f2eb-46f3-aae2-1dfa487d8312)
59+
![image](https://github.com/user-attachments/assets/dedce85a-b26e-419c-b740-a42984a06238)
4660

61+
`renderSingleMsgBox()` function is an `async` function. And `render()` will not use `await` to call that function, means if we do nothing, two `renderSingleMsgBox()` could be called at the same time to process the same message box. To ensure only one `renderSingleMsgBox()` function called for each message box, we could put the Rendered detection at the begining of the function:
4762

48-
After the process above, we will get a list of `MsgProcessInfo` object. What we need to do is:
63+
```js
64+
// skip rendered message
65+
if (messageBox.classList.contains(markdownRenderedClassName)) {
66+
return;
67+
}
68+
// mark current message as rendered
69+
messageBox.classList.add(markdownRenderedClassName);
70+
```
71+
72+
# Global & MessageRendered Callback
4973

50-
- First, accumulate all `mark` from the list, passed it to *Markdown Renderer*, then get a `renderedHtml`.
51-
- Iterating `replace` field of `MsgProcessInfo` list, if not `undefined`, execute the replace function.
74+
- For the task that need to be done directly after a message is rendered, put it at the end of `renderSingleMsgBox()` function.
75+
- For the task that need to be done after a whole rendering is finished, put it at the end of `renderer()` function.
76+
77+
> TODO:
78+
>
79+
> Add a more general callback protocol and manager for rendering process.
5280
5381
# Refs
5482

5583
For more info about the process, check out source code file:
5684

5785
- [msgpiece_processor.ts](/src/render/msgpiece_processor.ts)
58-
- [renderer.jsx](/src/renderer.jsx)
86+
- [renderer.tsx](/src/renderer.tsx)
87+
88+
For outdated doc:
89+
90+
- [Message Rendering Process Doc 2.3.5](./msg_rendering_process_2.3.5.md)

0 commit comments

Comments
 (0)