added static and framed external rendering (untested)

This commit is contained in:
2026-02-24 23:20:56 -07:00
parent 8c2eb1bf80
commit 4652569aee
7 changed files with 138 additions and 5 deletions
+93
View File
@@ -11,11 +11,15 @@
package ui
import (
"bytes"
"embed"
"io"
"io/fs"
"net/http"
"strings"
"github.com/labstack/echo/v4"
"golang.org/x/net/html"
)
//go:embed static/*
@@ -29,3 +33,92 @@ func AmStaticFileHandler() echo.HandlerFunc {
}
return echo.WrapHandler(http.StripPrefix("/static/", http.FileServer(http.FS(fsys))))
}
// extractPlainText extracts all plain text from a HTML tree node.
func extractPlainText(n *html.Node) string {
var sb strings.Builder
var walk func(*html.Node)
walk = func(n *html.Node) {
if n.Type == html.TextNode {
sb.WriteString(n.Data)
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
walk(c)
}
}
walk(n)
return sb.String()
}
// extractInnerHTML extracts the inner HTML from a HTML tree node.
func extractInnerHTML(n *html.Node) string {
var buf bytes.Buffer
for c := n.FirstChild; c != nil; c = c.NextSibling {
html.Render(&buf, c)
}
return buf.String()
}
// breakUpHTML extracts the title and body from an HTML page.
func breakUpHTML(r io.Reader) (string, string, error) {
doc, err := html.Parse(r)
if err != nil {
return "", "", err
}
title := ""
body := ""
var traverse func(*html.Node)
traverse = func(n *html.Node) {
if n.Type == html.ElementNode {
switch n.Data {
case "title":
body = extractPlainText(n)
case "body":
body = extractInnerHTML(n)
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
traverse(c)
}
}
traverse(doc)
return title, body, nil
}
/* AmStaticFramePage generates a handler that will serve up data from an external filesystem "framed" inside
* the frame with the template engine.
* Parameters:
* staticFS - The filesystem to serve from.
* prefix - The prefix to be stripped off pathnames to feed to the filesystem.
* Returns:
* An AmPageFunc suitable for wrapping and adding to the Echo handlers.
*/
func AmStaticFramePage(staticFS fs.FS, prefix string) AmPageFunc {
return func(ctxt AmContext) (string, any) {
fname := ctxt.URLPath()
if strings.HasPrefix(fname, prefix) {
fname = fname[len(prefix):]
} else {
return "error", "invalid path name"
}
mtype := mimeTypeFromFilename(fname)
ctxt.VarMap().Set("mimeType", mtype)
switch mtype {
case "text/html":
f, err := staticFS.Open(fname)
if err != nil {
return "error", err
}
defer f.Close()
title, body, err := breakUpHTML(f)
if err != nil {
return "error", err
}
ctxt.SetFrameTitle(title)
ctxt.VarMap().Set("title", title)
ctxt.VarMap().Set("data", body)
return "framed", "extern.jet"
}
return "error", "Unknown MIME Type: " + mtype
}
}
+20
View File
@@ -0,0 +1,20 @@
{*
* Amsterdam Web Communities System
* Copyright (c) 2025-2026 Erbosoft Metaverse Design Solutions, All Rights Reserved
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*}
<div class="p-4">
<!-- Page Title -->
<div class="mb-6">
<h1 class="text-blue-800 text-4xl font-bold mb-2">{{ title | raw }}</h1>
<hr class="border-2 border-gray-400 w-4/5 mb-6">
</div>
{{ if mimeType == "text/html" }}
{{ data | raw }}
{{ end }}
</div>