Markdown with supress <p>

This commit is contained in:
cyber-dream 2023-06-07 03:42:50 +03:00
parent b0c7b6a690
commit 2ba61f10ff
5 changed files with 192 additions and 135 deletions

View File

@ -2,10 +2,12 @@ package aboutme
import ( import (
"errors" "errors"
"html/template"
"net/http" "net/http"
"path" "path"
"personalwebsite/apps/appCtx" "personalwebsite/apps/appCtx"
"personalwebsite/errormessage" "personalwebsite/errormessage"
"personalwebsite/libs"
"personalwebsite/webfilesystem" "personalwebsite/webfilesystem"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -15,6 +17,7 @@ import (
type AboutMeApp struct { type AboutMeApp struct {
fs *webfilesystem.WebFileSystem fs *webfilesystem.WebFileSystem
appID string appID string
mLib libs.MarkdownLib
} }
func NewAboutMeApp(webFs *webfilesystem.WebFileSystem) *AboutMeApp { func NewAboutMeApp(webFs *webfilesystem.WebFileSystem) *AboutMeApp {
@ -54,12 +57,35 @@ func (p *AboutMeApp) PublicRoutes(route *gin.RouterGroup) {
func (p *AboutMeApp) PrivateRoutes(router *gin.RouterGroup) { func (p *AboutMeApp) PrivateRoutes(router *gin.RouterGroup) {
p.PublicRoutes(router) p.PublicRoutes(router)
router.GET("writeMock", func(ctx *gin.Context) { // router.GET("writeMock", func(ctx *gin.Context) {
err := p.WriteMock() // err := p.WriteMock()
if err != nil { // if err != nil {
ctx.Status(http.StatusInternalServerError) // ctx.Status(http.StatusInternalServerError)
} // }
ctx.Status(http.StatusOK) // ctx.Status(http.StatusOK)
// })
router.GET("getMock", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, PropertiesFileData{
Header: HeaderIsland{},
Islands: []Island{
{
Header: "qq",
Properties: []IslandProperty{
{
Key: "22",
KeyComments: []string{
"45",
"12",
},
Values: []string{
"aaaa",
},
},
},
},
},
})
}) })
router.GET("read", func(ctx *gin.Context) { router.GET("read", func(ctx *gin.Context) {
@ -93,7 +119,9 @@ func (p *AboutMeApp) PrivateRoutes(router *gin.RouterGroup) {
propsData := PropertiesFileData{} propsData := PropertiesFileData{}
err := ctx.BindJSON(&propsData) err := ctx.BindJSON(&propsData)
if err != nil { if err != nil {
ctx.Status(http.StatusBadRequest) ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: err.Error(),
})
return return
} }
@ -113,72 +141,72 @@ func (p *AboutMeApp) GetAppID() string {
return p.appID return p.appID
} }
func (p *AboutMeApp) WriteMock() error { // func (p *AboutMeApp) WriteMock() error {
fileHeader := webfilesystem.FileHeader{ // fileHeader := webfilesystem.FileHeader{
MongoId: primitive.NewObjectID(), // MongoId: primitive.NewObjectID(),
Name: "aboutme.props", // Name: "aboutme.props",
Type: "personal-properties", // Type: "personal-properties",
Icon: "", // Icon: "",
} // }
fileData := PropertiesFileData{ // fileData := PropertiesFileData{
Header: HeaderIsland{ // Header: HeaderIsland{
Name: "Test Name", // Name: "Test Name",
IconPath: "test icon path", // IconPath: "test icon path",
Info1: "Info1", // Info1: "Info1",
Info2: "Info2", // Info2: "Info2",
}, // },
Props: []PropIsland{ // Props: []PropIsland{
{ // {
Header: "Test Prop Header", // Header: "Test Prop Header",
Props: []PropElement{ // Props: []PropElement{
{ // {
Key: "Test key", // Key: "Test key",
KeyComments: []string{"Test key comment 1", "Test key comment 1"}, // KeyComments: []string{"Test key comment 1", "Test key comment 1"},
Values: []Value{ // Values: []Value{
{ // {
Blocks: []Block{ // Blocks: []ValueBlock{
{ // {
Type: "string", // Type: "string",
Data: []string{"aappo"}, // Data: []string{"aappo"},
}, // },
{ // {
Type: "link", // Type: "link",
Data: []string{"https://ya.ru", "Azazaza"}, // Data: []string{"https://ya.ru", "Azazaza"},
}, // },
}, // },
}, // },
}, // },
}, // },
}, // },
}, // },
{ // {
Header: "Test Prop Header 2", // Header: "Test Prop Header 2",
Props: []PropElement{ // Props: []PropElement{
{ // {
Key: "Test key", // Key: "Test key",
KeyComments: []string{"Test key comment 1", "Test key comment 1"}, // KeyComments: []string{"Test key comment 1", "Test key comment 1"},
Values: []Value{ // Values: []Value{
{ // {
Blocks: []Block{ // Blocks: []ValueBlock{
{ // {
Type: "string", // Type: "string",
Data: []string{"aappo"}, // Data: []string{"aappo"},
}, // },
{ // {
Type: "link", // Type: "link",
Data: []string{"https://ya.ru", "Azazaza"}, // Data: []string{"https://ya.ru", "Azazaza"},
}, // },
}, // },
}, // },
}, // },
}, // },
}, // },
}, // },
}, // },
} // }
_, _, err := p.fs.Write("/Applications/AboutMe.app/aboutme.props", &fileHeader, fileData) // _, _, err := p.fs.Write("/Applications/AboutMe.app/aboutme.props", &fileHeader, fileData)
return err // return err
} // }
func (p *AboutMeApp) Read(filePath string) (*PropertiesFileData, error) { func (p *AboutMeApp) Read(filePath string) (*PropertiesFileData, error) {
propData := PropertiesFileData{} propData := PropertiesFileData{}
@ -215,47 +243,84 @@ func (p *AboutMeApp) Edit(filePath string, blogData PropertiesFileData) error {
} }
func (p *AboutMeApp) Render(appCtx appCtx.AppContext, filePath string) (gin.H, error) { func (p *AboutMeApp) Render(appCtx appCtx.AppContext, filePath string) (gin.H, error) {
propsData := PropertiesFileData{} //Read file from WebFS
propsData := &PropertiesFileData{}
filePath = p.fs.RelativeToAbsolute(appCtx, filePath) filePath = p.fs.RelativeToAbsolute(appCtx, filePath)
_, err := p.fs.Read(filePath, &propsData) _, err := p.fs.Read(filePath, &propsData)
if err != nil { if err != nil {
return nil, err return nil, err
} }
//Render Markdown strings
renderedIslands := []RenderedIsland{}
for _, island := range propsData.Islands {
newRenderedIsland := RenderedIsland{
Header: island.Header,
Properties: []RenderedIslandProperty{},
}
for _, property := range island.Properties {
newRenderedIslandProperty := RenderedIslandProperty{
Key: property.Key,
KeyComments: property.KeyComments,
Values: []template.HTML{},
}
for _, value := range property.Values {
renderedValue := p.mLib.Render([]byte(value), true)
newRenderedIslandProperty.Values = append(newRenderedIslandProperty.Values, renderedValue)
}
newRenderedIsland.Properties = append(newRenderedIsland.Properties, newRenderedIslandProperty)
}
renderedIslands = append(renderedIslands, newRenderedIsland)
}
//Make icon path absolute
propsData.Header.IconPath = p.fs.RelativeToAbsolute(appCtx, propsData.Header.IconPath) propsData.Header.IconPath = p.fs.RelativeToAbsolute(appCtx, propsData.Header.IconPath)
return gin.H{ return gin.H{
"headerProps": propsData.Header, "HeaderProps": propsData.Header,
"allprops": propsData.Props, "Islands": renderedIslands,
}, nil }, nil
} }
type PropertiesFileData struct {
Header HeaderIsland `bson:"header"`
Islands []Island `bson:"islands"` //TODO rename
}
type HeaderIsland struct { type HeaderIsland struct {
Name string `bson:"name"` Name string `bson:"name"`
IconPath string `bson:"iconpath"` IconPath string `bson:"iconpath"`
Info1 string `bson:"info1"` Value1 string `bson:"value1"` //TODO Rename to value
Info2 string `bson:"info2"` Value2 string `bson:"value2"`
} }
type PropElement struct { type Island struct {
Header string `bson:"header"`
Properties []IslandProperty `bson:"properties"`
}
type IslandProperty struct {
Key string `bson:"key"`
KeyComments []string `bson:"keycomment"`
Values []string `bson:"values"`
}
type RenderedIsland struct {
Header string
Properties []RenderedIslandProperty
}
type RenderedIslandProperty struct {
Key string Key string
KeyComments []string KeyComments []string
Values []Value Values []template.HTML
} }
type Value struct { // type Value struct {
Blocks []Block // Blocks []ValueBlock
} // }
type Block struct { // type ValueBlock struct {
Type string // Type string
Data []string // Data string
} // }
type PropIsland struct {
Header string
Props []PropElement
}
type PropertiesFileData struct {
Header HeaderIsland `bson:"header"`
Props []PropIsland `bson:"props"`
}

View File

@ -45,7 +45,7 @@ func (b *BlogViewerApplication) PrivateRoutes(route *gin.RouterGroup) {
for _, block := range blogData.Blocks { for _, block := range blogData.Blocks {
for _, str := range block.Data { for _, str := range block.Data {
test := []byte(str) test := []byte(str)
mLib.Render(test) mLib.Render(test, true)
} }
} }
}) })
@ -239,7 +239,7 @@ func (b *BlogViewerApplication) Render(filePath string, appCtx appCtx.AppContext
// } // }
case "markdown": case "markdown":
for _, data := range block.Data { for _, data := range block.Data {
renderedMD := b.mLib.Render([]byte(data)) renderedMD := b.mLib.Render([]byte(data), true)
newBlock.Data = append(newBlock.Data, renderedMD) newBlock.Data = append(newBlock.Data, renderedMD)
} }
newData = append(newData, newBlock) newData = append(newData, newBlock)

View File

@ -2,6 +2,7 @@ package libs
import ( import (
"html/template" "html/template"
"strings"
"github.com/microcosm-cc/bluemonday" "github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday/v2" "github.com/russross/blackfriday/v2"
@ -10,8 +11,12 @@ import (
type MarkdownLib struct { type MarkdownLib struct {
} }
func (ml *MarkdownLib) Render(s []byte) template.HTML { func (ml *MarkdownLib) Render(md []byte, supressParagraph bool) template.HTML {
output := blackfriday.Run(s) output := blackfriday.Run(md)
if supressParagraph {
output = []byte(strings.ReplaceAll(string(output), "<p>", ""))
output = []byte(strings.ReplaceAll(string(output), "</p>", ""))
}
_ = output _ = output
html := bluemonday.UGCPolicy().SanitizeBytes(output) html := bluemonday.UGCPolicy().SanitizeBytes(output)
// println(string(html)) // println(string(html))

View File

@ -42,17 +42,17 @@ func PrivateRoutes(port string, webfs *webfilesystem.WebFileSystem, webde *wde.W
Args: []string{"/home/user/Blogs/blog1.blog"}, Args: []string{"/home/user/Blogs/blog1.blog"},
} }
// aboutMe := AppString{ aboutMe := AppString{
// AppPath: "/Applications/AboutMe.app", AppPath: "/Applications/AboutMe.app",
// Args: []string{}, Args: []string{},
// } }
// appString2 := AppString{ // appString2 := AppString{
// AppPath: "/Applications/Finder.app", // AppPath: "/Applications/Finder.app",
// Args: []string{"/home/user/", "--desktop", "desktop-layer"}, // Args: []string{"/home/user/", "--desktop", "desktop-layer"},
// } // }
autostart := []AppString{appString} autostart := []AppString{appString, aboutMe}
ctx.HTML(http.StatusOK, "index.tmpl", gin.H{ ctx.HTML(http.StatusOK, "index.tmpl", gin.H{
"autostart": autostart, "autostart": autostart,
}) })

View File

@ -12,44 +12,31 @@
<div class="PropsView"> <div class="PropsView">
<div class="PropertiesList"> <div class="PropertiesList">
<div class="ShortBio"> <div class="ShortBio">
<img class="Image" src="/system/libs/img/get?path={{ .headerProps.IconPath }}" alt="My Photo"> <img class="Image" src="/system/libs/img/get?path={{ .HeaderProps.IconPath }}" alt="My Photo">
<div class="Text"> <div class="Text">
<div class="Name">{{ .headerProps.Name }}</div> <div class="Name">{{ .HeaderProps.Name }}</div>
<div>{{ .headerProps.Info1 }}</div> <div>{{ .HeaderProps.Value1 }}</div>
<div>{{ .headerProps.Info2 }}</div> <div>{{ .HeaderProps.Value2 }}</div>
</div> </div>
</div> </div>
{{ range $propIsland := .allprops }} {{ range $island := .Islands }}
<!-- FIXME --> <!-- FIXME -->
<div class="Island">
<div class="Title"> <div class="Island">
{{$propIsland.Header}}: <div class="Title"> {{$island.Header}}:</div>
</div>
<div class="Content"> <div class="Content">
{{range $prop := $propIsland.Props}}
{{range $property := $island.Properties}}
<div class="Row"> <div class="Row">
<div class="Key"> <div class="Key">
{{$prop.Key}}: {{$property.Key}}:
{{ range $keyComment := $prop.KeyComments }} {{ range $keyComment := $property.KeyComments }}
<div class="KeyComment"> <div class="KeyComment">{{ $keyComment }}</div>
{{ $keyComment }}
</div>
{{ end }} {{ end }}
</div> </div>
<div class="Values"> <div class="Values">
{{ range $value := $prop.Values }} {{ range $value := $property.Values }}
<div class="Value"> <div class="Value">{{ $value }}</div>
{{ range $block := $value.Blocks }}
{{ if eq $block.Type "link"}}
<a href="{{ index $block.Data 0}}">{{ index $block.Data 1}}</a>
{{ end }}
{{ if eq $block.Type "string"}}
{{ range $string := $block.Data}}
{{ $string }}
{{ end }}
{{ end }}
{{ end }}
</div>
{{ end }} {{ end }}
</div> </div>
</div> </div>