diff --git a/frontend/index.html b/frontend/index.html index 000b63d..cd66cbf 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -39,6 +39,7 @@ window.uploadPrompt = `{{UploadPrompt}}`; window.allowNormalUserUpload = `{{AllowNormalUserUpload}}`; +
diff --git a/frontend/src/app.ts b/frontend/src/app.ts index 6773036..625a369 100644 --- a/frontend/src/app.ts +++ b/frontend/src/app.ts @@ -63,6 +63,21 @@ class App { canUpload() { return this.isLoggedIn() && (this.user?.can_upload || this.isAdmin()); } + + getPreFetchData() { + const preFetchDataElement = document.getElementById("pre_fetch_data"); + if (preFetchDataElement) { + let content = preFetchDataElement.textContent + if (!content) { + return null; + } + content = decodeURIComponent(content); + const res = JSON.parse(content); + preFetchDataElement.remove(); + return res; + } + return null; + } } export const app = new App(); diff --git a/frontend/src/pages/comment_page.tsx b/frontend/src/pages/comment_page.tsx index 6dca143..31ade02 100644 --- a/frontend/src/pages/comment_page.tsx +++ b/frontend/src/pages/comment_page.tsx @@ -54,6 +54,11 @@ export default function CommentPage() { }); return; } + const preFetchData = app.getPreFetchData(); + if (preFetchData?.comment?.id === id) { + setComment(preFetchData.comment); + return; + } network.getComment(id).then((res) => { if (res.success) { setComment(res.data!); diff --git a/frontend/src/pages/resource_details_page.tsx b/frontend/src/pages/resource_details_page.tsx index b5a8504..c82c24f 100644 --- a/frontend/src/pages/resource_details_page.tsx +++ b/frontend/src/pages/resource_details_page.tsx @@ -90,14 +90,19 @@ export default function ResourcePage() { if (location.state) { setResource(location.state.resource); } else { - network.getResourceDetails(id).then((res) => { - if (res.success) { - setResource(res.data!); - document.title = res.data!.title; - } else { - showToast({ message: res.message, type: "error" }); - } - }); + const preFetchData = app.getPreFetchData(); + if (preFetchData?.resource?.id === id) { + setResource(preFetchData.resource); + } else { + network.getResourceDetails(id).then((res) => { + if (res.success) { + setResource(res.data!); + document.title = res.data!.title; + } else { + showToast({ message: res.message, type: "error" }); + } + }); + } } } }, [id, location.state]); diff --git a/frontend/src/pages/user_page.tsx b/frontend/src/pages/user_page.tsx index 7f6d0d6..410dcb7 100644 --- a/frontend/src/pages/user_page.tsx +++ b/frontend/src/pages/user_page.tsx @@ -14,6 +14,7 @@ import { MdOutlinePhotoAlbum, } from "react-icons/md"; import { useTranslation } from "react-i18next"; +import { app } from "../app.ts"; export default function UserPage() { const [user, setUser] = useState(null); @@ -50,6 +51,11 @@ export default function UserPage() { }; useEffect(() => { + const preFetchData = app.getPreFetchData(); + if (preFetchData?.user?.username === username) { + setUser(preFetchData.user); + return; + } network.getUserInfo(username || "").then((res) => { if (res.success) { setUser(res.data!); diff --git a/server/middleware/frontend_middleware.go b/server/middleware/frontend_middleware.go index 3f4e9f6..c2a7739 100644 --- a/server/middleware/frontend_middleware.go +++ b/server/middleware/frontend_middleware.go @@ -1,8 +1,9 @@ package middleware import ( + "encoding/json" "fmt" - url2 "net/url" + "net/url" "nysoure/server/config" "nysoure/server/service" "nysoure/server/utils" @@ -68,22 +69,27 @@ func serveIndexHtml(c fiber.Ctx) error { description := config.ServerDescription() preview := serverBaseURL + "/icon-192.png" title := siteName - url := serverBaseURL + c.Path() + htmlUrl := serverBaseURL + c.Path() cfTurnstileSiteKey := config.CloudflareTurnstileSiteKey() siteInfo := config.SiteInfo() path := c.Path() + preFetchData := "" if strings.HasPrefix(path, "/resources/") { idStr := strings.TrimPrefix(path, "/resources/") id, err := strconv.Atoi(idStr) if err == nil { - r, err := service.GetResource(uint(id), "") + r, err := service.GetResource(uint(id), c.Hostname()) if err == nil { if len(r.Images) > 0 { preview = fmt.Sprintf("%s/api/image/%d", serverBaseURL, r.Images[0].ID) } title = r.Title description = utils.ArticleToDescription(r.Article, 200) + preFetchDataJson, _ := json.Marshal(map[string]interface{}{ + "resource": r, + }) + preFetchData = url.QueryEscape(string(preFetchDataJson)) } } } else if strings.HasPrefix(path, "/user/") { @@ -93,10 +99,14 @@ func serveIndexHtml(c fiber.Ctx) error { preview = fmt.Sprintf("%s/api/avatar/%d", serverBaseURL, u.ID) title = u.Username description = "User " + u.Username + "'s profile" + preFetchDataJson, _ := json.Marshal(map[string]interface{}{ + "user": u, + }) + preFetchData = url.QueryEscape(string(preFetchDataJson)) } } else if strings.HasPrefix(path, "/tag/") { tagName := strings.TrimPrefix(path, "/tag/") - tagName, err := url2.PathUnescape(tagName) + tagName, err := url.PathUnescape(tagName) tagName = strings.TrimSpace(tagName) if err == nil { t, err := service.GetTagByName(tagName) @@ -117,6 +127,10 @@ func serveIndexHtml(c fiber.Ctx) error { if len(cmt.Images) > 0 { preview = fmt.Sprintf("%s/api/image/%d", serverBaseURL, cmt.Images[0].ID) } + preFetchDataJson, _ := json.Marshal(map[string]interface{}{ + "comment": cmt, + }) + preFetchData = url.QueryEscape(string(preFetchDataJson)) } } } @@ -125,11 +139,12 @@ func serveIndexHtml(c fiber.Ctx) error { content = strings.ReplaceAll(content, "{{Description}}", description) content = strings.ReplaceAll(content, "{{Preview}}", preview) content = strings.ReplaceAll(content, "{{Title}}", title) - content = strings.ReplaceAll(content, "{{Url}}", url) + content = strings.ReplaceAll(content, "{{Url}}", htmlUrl) content = strings.ReplaceAll(content, "{{CFTurnstileSiteKey}}", cfTurnstileSiteKey) content = strings.ReplaceAll(content, "{{SiteInfo}}", siteInfo) content = strings.ReplaceAll(content, "{{UploadPrompt}}", config.UploadPrompt()) content = strings.ReplaceAll(content, "{{AllowNormalUserUpload}}", strconv.FormatBool(config.AllowNormalUserUpload())) + content = strings.ReplaceAll(content, "", fmt.Sprintf("", preFetchData)) c.Set("Content-Type", "text/html; charset=utf-8") return c.SendString(content)