mirror of
https://github.com/siyuan-note/siyuan.git
synced 2025-12-16 14:40:12 +01:00
🎨 Improve exporting document HTML (#16219)
* 🎨 The browser-side supports exporting document HTML fix https://github.com/siyuan-note/siyuan/issues/16213 * 修复导出 HTML 时引入资源没有使用相对路径,修复文档导出 HTML/PDF 时缺失图标 fix https://github.com/siyuan-note/siyuan/issues/16217 fix https://github.com/siyuan-note/siyuan/issues/16216 01 * 修复文档导出 HTML/PDF 时冗余图标 fix https://github.com/siyuan-note/siyuan/issues/16216 02
This commit is contained in:
parent
bca1f1eda6
commit
90a447f914
6 changed files with 241 additions and 40 deletions
|
|
@ -20,6 +20,7 @@ import (
|
|||
"io"
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
|
@ -30,6 +31,7 @@ import (
|
|||
"github.com/88250/lute/parse"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/mssola/useragent"
|
||||
"github.com/siyuan-note/filelock"
|
||||
"github.com/siyuan-note/logging"
|
||||
"github.com/siyuan-note/siyuan/kernel/model"
|
||||
"github.com/siyuan-note/siyuan/kernel/util"
|
||||
|
|
@ -489,6 +491,21 @@ func exportMdHTML(c *gin.Context) {
|
|||
|
||||
id := arg["id"].(string)
|
||||
savePath := arg["savePath"].(string)
|
||||
|
||||
savePath = strings.TrimSpace(savePath)
|
||||
if savePath == "" {
|
||||
folderName := "htmlmd-" + id + "-" + util.CurrentTimeSecondsStr()
|
||||
tmpDir := filepath.Join(util.TempDir, "export", folderName)
|
||||
name, content := model.ExportMarkdownHTML(id, tmpDir, false, false)
|
||||
ret.Data = map[string]interface{}{
|
||||
"id": id,
|
||||
"name": name,
|
||||
"content": content,
|
||||
"folder": folderName,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
name, content := model.ExportMarkdownHTML(id, savePath, false, false)
|
||||
ret.Data = map[string]interface{}{
|
||||
"id": id,
|
||||
|
|
@ -527,6 +544,62 @@ func exportTempContent(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
func exportBrowserHTML(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
||||
arg, ok := util.JsonArg(c, ret)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
folder := arg["folder"].(string)
|
||||
htmlContent := arg["html"].(string)
|
||||
name := arg["name"].(string)
|
||||
|
||||
tmpDir := filepath.Join(util.TempDir, "export", folder)
|
||||
|
||||
htmlPath := filepath.Join(tmpDir, "index.html")
|
||||
if err := filelock.WriteFile(htmlPath, []byte(htmlContent)); err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
ret.Data = nil
|
||||
return
|
||||
}
|
||||
|
||||
zipFileName := util.FilterFileName(name) + ".zip"
|
||||
zipPath := filepath.Join(util.TempDir, "export", zipFileName)
|
||||
zip, err := gulu.Zip.Create(zipPath)
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
ret.Data = nil
|
||||
return
|
||||
}
|
||||
|
||||
err = zip.AddDirectory("", tmpDir, func(string) {})
|
||||
if err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
ret.Data = nil
|
||||
return
|
||||
}
|
||||
|
||||
if err = zip.Close(); err != nil {
|
||||
ret.Code = -1
|
||||
ret.Msg = err.Error()
|
||||
ret.Data = nil
|
||||
return
|
||||
}
|
||||
|
||||
os.RemoveAll(tmpDir)
|
||||
|
||||
zipURL := "/export/" + url.PathEscape(filepath.Base(zipPath))
|
||||
ret.Data = map[string]interface{}{
|
||||
"zip": zipURL,
|
||||
}
|
||||
}
|
||||
|
||||
func exportPreviewHTML(c *gin.Context) {
|
||||
ret := gulu.Ret.NewResult()
|
||||
defer c.JSON(http.StatusOK, ret)
|
||||
|
|
@ -590,6 +663,21 @@ func exportHTML(c *gin.Context) {
|
|||
if nil != arg["merge"] {
|
||||
merge = arg["merge"].(bool)
|
||||
}
|
||||
|
||||
savePath = strings.TrimSpace(savePath)
|
||||
if savePath == "" {
|
||||
folderName := "html-" + id + "-" + util.CurrentTimeSecondsStr()
|
||||
tmpDir := filepath.Join(util.TempDir, "export", folderName)
|
||||
name, content, _ := model.ExportHTML(id, tmpDir, pdf, false, keepFold, merge)
|
||||
ret.Data = map[string]interface{}{
|
||||
"id": id,
|
||||
"name": name,
|
||||
"content": content,
|
||||
"folder": folderName,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
name, content, _ := model.ExportHTML(id, savePath, pdf, false, keepFold, merge)
|
||||
ret.Data = map[string]interface{}{
|
||||
"id": id,
|
||||
|
|
|
|||
|
|
@ -325,6 +325,7 @@ func ServeAPI(ginServer *gin.Engine) {
|
|||
ginServer.Handle("POST", "/api/export/exportData", model.CheckAuth, model.CheckAdminRole, exportData)
|
||||
ginServer.Handle("POST", "/api/export/exportDataInFolder", model.CheckAuth, model.CheckAdminRole, exportDataInFolder)
|
||||
ginServer.Handle("POST", "/api/export/exportTempContent", model.CheckAuth, model.CheckAdminRole, exportTempContent)
|
||||
ginServer.Handle("POST", "/api/export/exportBrowserHTML", model.CheckAuth, model.CheckAdminRole, exportBrowserHTML)
|
||||
ginServer.Handle("POST", "/api/export/export2Liandi", model.CheckAuth, model.CheckAdminRole, model.CheckReadonly, export2Liandi)
|
||||
ginServer.Handle("POST", "/api/export/exportReStructuredText", model.CheckAuth, model.CheckAdminRole, exportReStructuredText)
|
||||
ginServer.Handle("POST", "/api/export/exportAsciiDoc", model.CheckAuth, model.CheckAdminRole, exportAsciiDoc)
|
||||
|
|
|
|||
|
|
@ -766,7 +766,8 @@ func ExportMarkdownHTML(id, savePath string, docx, merge bool) (name, dom string
|
|||
if 1 == Conf.Appearance.Mode {
|
||||
theme = Conf.Appearance.ThemeDark
|
||||
}
|
||||
srcs = []string{"icons", "themes/" + theme}
|
||||
// 复制主题文件夹
|
||||
srcs = []string{"themes/" + theme}
|
||||
appearancePath := util.AppearancePath
|
||||
if util.IsSymlinkPath(util.AppearancePath) {
|
||||
// Support for symlinked theme folder when exporting HTML https://github.com/siyuan-note/siyuan/issues/9173
|
||||
|
|
@ -787,6 +788,35 @@ func ExportMarkdownHTML(id, savePath string, docx, merge bool) (name, dom string
|
|||
}
|
||||
}
|
||||
|
||||
// 只复制图标文件夹中的 icon.js 文件
|
||||
iconName := Conf.Appearance.Icon
|
||||
// 如果使用的不是内建图标(ant 或 material),需要复制 material 作为后备
|
||||
if iconName != "ant" && iconName != "material" && iconName != "" {
|
||||
srcIconFile := filepath.Join(appearancePath, "icons", "material", "icon.js")
|
||||
toIconDir := filepath.Join(savePath, "appearance", "icons", "material")
|
||||
if err := os.MkdirAll(toIconDir, 0755); err != nil {
|
||||
logging.LogErrorf("mkdir [%s] failed: %s", toIconDir, err)
|
||||
return
|
||||
}
|
||||
toIconFile := filepath.Join(toIconDir, "icon.js")
|
||||
if err := filelock.Copy(srcIconFile, toIconFile); err != nil {
|
||||
logging.LogWarnf("copy icon file from [%s] to [%s] failed: %s", srcIconFile, toIconFile, err)
|
||||
}
|
||||
}
|
||||
// 复制当前使用的图标文件
|
||||
if iconName != "" {
|
||||
srcIconFile := filepath.Join(appearancePath, "icons", iconName, "icon.js")
|
||||
toIconDir := filepath.Join(savePath, "appearance", "icons", iconName)
|
||||
if err := os.MkdirAll(toIconDir, 0755); err != nil {
|
||||
logging.LogErrorf("mkdir [%s] failed: %s", toIconDir, err)
|
||||
return
|
||||
}
|
||||
toIconFile := filepath.Join(toIconDir, "icon.js")
|
||||
if err := filelock.Copy(srcIconFile, toIconFile); err != nil {
|
||||
logging.LogWarnf("copy icon file from [%s] to [%s] failed: %s", srcIconFile, toIconFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 复制自定义表情图片
|
||||
emojis := emojisInTree(tree)
|
||||
for _, emoji := range emojis {
|
||||
|
|
@ -930,7 +960,8 @@ func ExportHTML(id, savePath string, pdf, image, keepFold, merge bool) (name, do
|
|||
if 1 == Conf.Appearance.Mode {
|
||||
theme = Conf.Appearance.ThemeDark
|
||||
}
|
||||
srcs = []string{"icons", "themes/" + theme}
|
||||
// 复制主题文件夹
|
||||
srcs = []string{"themes/" + theme}
|
||||
appearancePath := util.AppearancePath
|
||||
if util.IsSymlinkPath(util.AppearancePath) {
|
||||
// Support for symlinked theme folder when exporting HTML https://github.com/siyuan-note/siyuan/issues/9173
|
||||
|
|
@ -949,6 +980,35 @@ func ExportHTML(id, savePath string, pdf, image, keepFold, merge bool) (name, do
|
|||
}
|
||||
}
|
||||
|
||||
// 只复制图标文件夹中的 icon.js 文件
|
||||
iconName := Conf.Appearance.Icon
|
||||
// 如果使用的不是内建图标(ant 或 material),需要复制 material 作为后备
|
||||
if iconName != "ant" && iconName != "material" && iconName != "" {
|
||||
srcIconFile := filepath.Join(appearancePath, "icons", "material", "icon.js")
|
||||
toIconDir := filepath.Join(savePath, "appearance", "icons", "material")
|
||||
if err := os.MkdirAll(toIconDir, 0755); err != nil {
|
||||
logging.LogErrorf("mkdir [%s] failed: %s", toIconDir, err)
|
||||
return
|
||||
}
|
||||
toIconFile := filepath.Join(toIconDir, "icon.js")
|
||||
if err := filelock.Copy(srcIconFile, toIconFile); err != nil {
|
||||
logging.LogWarnf("copy icon file from [%s] to [%s] failed: %s", srcIconFile, toIconFile, err)
|
||||
}
|
||||
}
|
||||
// 复制当前使用的图标文件
|
||||
if iconName != "" {
|
||||
srcIconFile := filepath.Join(appearancePath, "icons", iconName, "icon.js")
|
||||
toIconDir := filepath.Join(savePath, "appearance", "icons", iconName)
|
||||
if err := os.MkdirAll(toIconDir, 0755); err != nil {
|
||||
logging.LogErrorf("mkdir [%s] failed: %s", toIconDir, err)
|
||||
return
|
||||
}
|
||||
toIconFile := filepath.Join(toIconDir, "icon.js")
|
||||
if err := filelock.Copy(srcIconFile, toIconFile); err != nil {
|
||||
logging.LogWarnf("copy icon file from [%s] to [%s] failed: %s", srcIconFile, toIconFile, err)
|
||||
}
|
||||
}
|
||||
|
||||
// 复制自定义表情图片
|
||||
emojis := emojisInTree(tree)
|
||||
for _, emoji := range emojis {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue