Skip to content

Commit

Permalink
Merge pull request #66 from d0j1a1701/nf_dev
Browse files Browse the repository at this point in the history
- refactor: Refactor the structure of renderer.

To know more about how new render process work, checkout `docs\dev\msg_rendering_process.md`.

- fix: Fix the image rendering issue. (#37)

However, adding image to message may sometimes broke other Markdown & LaTeX rendering process. It's recommend always add linebreak before and after image if you want the message be correctly rendered into Markdown.

- docs: Update relevant docs.
  • Loading branch information
nfnfgo authored Jul 12, 2024
2 parents 0828369 + 18db30b commit 7ceb180
Show file tree
Hide file tree
Showing 10 changed files with 520 additions and 132 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,7 @@ Normal test with HTML Entities & " ' < > .
## 注意事项

- 如果在使用插件时遇到问题,您可以通过 [发起 Issue](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/issues/new) 向我们进行反馈。届时请尽可能附上诸如系统版本,插件列表, LiteLoaderQQNT 设置页版本信息截图等可以帮助分析问题的信息。如果你还安装了远程调试插件,可以再附上 Devtools 信息。

## Contributing

如果您想要为本项目贡献代码,或者想了解本项目的代码相关细节,欢迎阅读 [项目开发文档](/docs/dev/renderer.md)
1 change: 1 addition & 0 deletions diagram/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.bkp
134 changes: 134 additions & 0 deletions diagram/frag_processor.drawio
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<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">
<diagram name="Page-1" id="zotAlQJJTCq7FzbI9wUf">
<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">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="8dtW_6vD572V2-CuLths-22" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="395" y="240" width="130" height="260" as="geometry" />
</mxCell>
<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">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-20" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#f5f5f5;strokeColor=#666666;fontColor=#333333;" vertex="1" parent="1">
<mxGeometry x="580" y="240" width="200" height="260" as="geometry" />
</mxCell>
<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">
<mxGeometry relative="1" as="geometry">
<mxPoint x="400" y="365" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-1" value="MsgBox" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="280" y="291.25" width="80" height="147.5" as="geometry" />
</mxCell>
<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">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-2" value="SPAN text" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="420" y="265" width="80" height="40" as="geometry" />
</mxCell>
<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">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="550" y="335" />
<mxPoint x="550" y="285" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-3" value="SPAN text" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="420" y="315" width="80" height="40" as="geometry" />
</mxCell>
<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">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="570" y="385" />
<mxPoint x="570" y="335" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-4" value="SPAN other" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="420" y="365" width="80" height="40" as="geometry" />
</mxCell>
<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">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-5" value="DIV other" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="420" y="415" width="80" height="40" as="geometry" />
</mxCell>
<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">
<mxGeometry x="430" y="465" width="60" height="30" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-11" value="textSpanProcessor" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="600" y="265" width="160" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-12" value="spanReplaceProcessor" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="600" y="315" width="160" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-13" value="..." style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="600" y="365" width="160" height="40" as="geometry" />
</mxCell>
<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">
<mxGeometry x="600" y="415" width="160" height="40" as="geometry" />
</mxCell>
<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">
<mxGeometry x="630" y="460" width="100" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-28" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="830" y="240" width="190" height="260" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-23" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="856.63" y="265" width="133.37" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-24" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="856.63" y="315" width="133.37" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-25" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="856.63" y="365" width="133.37" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-27" value="..." style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="856.63" y="415" width="133.37" height="40" as="geometry" />
</mxCell>
<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">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<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">
<mxGeometry x="0.0165" y="1" relative="1" as="geometry">
<mxPoint x="-1" y="1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-32" value="" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#dae8fc;strokeColor=#6c8ebf;" vertex="1" parent="1">
<mxGeometry x="280" y="600" width="190" height="260" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-33" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="306.63" y="630" width="133.37" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-34" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="306.63" y="681.25" width="133.37" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-35" value="{mark: ..., replace: ...}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="306.63" y="735" width="133.37" height="40" as="geometry" />
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-36" value="..." style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="306.63" y="790" width="133.37" height="40" as="geometry" />
</mxCell>
<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">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<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">
<mxGeometry x="-0.2279" relative="1" as="geometry">
<mxPoint x="9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="8dtW_6vD572V2-CuLths-37" value="Markdown It Renderer" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="580" y="700" width="170" height="60" as="geometry" />
</mxCell>
<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">
<mxGeometry x="856.63" y="700" width="170" height="60" as="geometry" />
</mxCell>
<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">
<mxGeometry x="873.3099999999998" y="460" width="100" height="40" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>
58 changes: 58 additions & 0 deletions docs/dev/msg_rendering_process.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
- [Workflow](#workflow)
- [MsgProcessInfo](#msgprocessinfo)
- [FragmentProcessFunc](#fragmentprocessfunc)
- [Refs](#refs)


# Workflow

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*.

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

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.

## MsgProcessInfo

This refers to object like: `{mark:..., replace:...}`:

- `mark` Determine how it looks like for Markdown Renderer.
- `replace` Determine replace behaviour after markdown render process.

This decide what this element looks like when passed to Markdown Renderer. For example, an element `<span>123</span>` should converted to:

```js
{mark: '123', replace: undefined}
```

And an element that should be replaced later `<img class="face-element__icon"></img>` could be converted to:

```js
{
mark: '<span id="some_placeholder"></span>',
replace: (parent)=>{...}
}
```

## FragmentProcessFunc

The work of generating `MsgProcessInfo` based on HTML pieces is done by a set of function with type `FragmentProcessFunc`.

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.

-----

![image](https://github.com/d0j1a1701/LiteLoaderQQNT-Markdown/assets/61616918/04247260-f2eb-46f3-aae2-1dfa487d8312)


After the process above, we will get a list of `MsgProcessInfo` object. What we need to do is:

- First, accumulate all `mark` from the list, passed it to *Markdown Renderer*, then get a `renderedHtml`.
- Iterating `replace` field of `MsgProcessInfo` list, if not `undefined`, execute the replace function.

# Refs

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

- [msgpiece_processor.ts](/src/render/msgpiece_processor.ts)
- [renderer.jsx](/src/renderer.jsx)
9 changes: 8 additions & 1 deletion docs/dev/renderer.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
![React](https://img.shields.io/badge/React-blue?style=for-the-badge&logo=react&logoColor=white)
![JavaScript](https://img.shields.io/badge/JavaScript-yellow?style=for-the-badge&logo=javascript&logoColor=white)
![Typescript](https://img.shields.io/badge/TypeScript-blue?style=for-the-badge&logo=typescript&logoColor=white)
![Webpack](https://img.shields.io/badge/Webpack-grey?style=for-the-badge&logo=react&logoColor=white)
![Webpack](https://img.shields.io/badge/Webpack-grey?style=for-the-badge&logo=webpack&logoColor=white)

- [Introduction](#introduction)
- [Start Developing](#start-developing)
- [Logging](#logging)
- [Create Release Version](#create-release-version)
- [UI Development](#ui-development)
- [Read More](#read-more)
- [Content Rendering Test Example](#content-rendering-test-example)


Expand Down Expand Up @@ -78,6 +79,12 @@ Currently only `.js` file extension is supported, using `.jsx` may cause webpack

> This might be solved by provide custom package resolve rules to webpack but I didn't look into it.
# Read More

[Message Rendering Process](./msg_rendering_process.md)

[HTML Entities Processing](./msg_rendering_process.md)

# Content Rendering Test Example

You could use Markdown below as a quick Markdown Rendering Test.
Expand Down
29 changes: 29 additions & 0 deletions docs/known_issue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
This document is used to record some Known Issue of this plugin.

# Compatability Issue With Other Plugin

Currently we found that sometimes it would cause incorrect rendering behaviour when using this plugin with `LiteTools`(another QQNT plugin). And user may experience:

- Incorrect LiteTools Slot rendering position. For example, the *Message Send Time* and *Withdrawed* slot may be rendered with incorrect position / alignment.

Currently the workaround for the LiteTool Time slot is to use JavaScript to observe the `offsetHeight` of each message box. If it over a specific value, we consider this message a multiple-line message and set the `flex-direction: column` to the root message box, otherwise set `flex-direction: row`.

This require change message box div into `flex` which may cause other rendering issue, and this workaround should be replaced by a better solution.

# Post Rendering Function Exec Order Issue

Currently, we call `renderSingleMsgBox()` function inside `render()`, then after we call some post-rendering functions, the whole process is like:

```js
msgBoxs.forEach((box){
renderSingleMsgBox(box); // actually async
})

// these function may run first before every msgbox finish rendering
changeDirectionToColumnWhenLargerHeight();
elementDebugLogger();
```

However the issue is the *MarkdownIt* render function returns Promise, so the `renderSingleMsgBox()` is an async function. And so, the post-rendering function below actually may run first while the message is not fully rendererd.

Currently we do NOT implement any workaround on this since the test show this issue don't affect the rendering result for now. However this is something that should be fixed in the future.
Loading

0 comments on commit 7ceb180

Please sign in to comment.