diff --git a/assets/js/controllers/postedit.js b/assets/js/controllers/postedit.js index 54679c5..71328e3 100644 --- a/assets/js/controllers/postedit.js +++ b/assets/js/controllers/postedit.js @@ -14,11 +14,16 @@ export default class PosteditController extends Controller { async save(ev) { ev.preventDefault(); + showToast({ + title: "💾 Saving Post", + body: (this.saveActionValue === "Save Draft") ? "Saving post as draft…" : "Updating post…", + }); + try { await this._postForm(this.saveActionValue); showToast({ - title: "💾 Post Saved", + title: "💾 Saving Post", body: (this.saveActionValue === "Save Draft") ? "Post saved as draft." : "Post updated.", }); } catch (e) { diff --git a/providers/sitebuilder/builder.go b/providers/sitebuilder/builder.go index 9b25fb1..4908d61 100644 --- a/providers/sitebuilder/builder.go +++ b/providers/sitebuilder/builder.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/PuerkitoBio/goquery" "github.com/gopherlibs/feedhub/feedhub" "golang.org/x/sync/errgroup" "lmika.dev/lmika/weiro/models" @@ -20,10 +21,11 @@ import ( ) type Builder struct { - site pubmodel.Site - mdRenderer *markdown.Renderer - opts Options - tmpls *template.Template + site pubmodel.Site + mdRenderer *markdown.Renderer + opts Options + tmpls *template.Template + postMDProcessors []postMDProcessor } func New(site pubmodel.Site, opts Options) (*Builder, error) { @@ -39,6 +41,9 @@ func New(site pubmodel.Site, opts Options) (*Builder, error) { opts: opts, tmpls: tmpls, mdRenderer: markdown.NewRendererForSite(), + postMDProcessors: []postMDProcessor{ + uploadAbsoluteURL, + }, }, nil } @@ -207,6 +212,26 @@ func (b *Builder) renderPost(post *models.Post) (postSingleData, error) { return postSingleData{}, fmt.Errorf("failed to write post %s: %w", post.Slug, err) } + if len(b.postMDProcessors) > 0 { + dom, err := goquery.NewDocumentFromReader(&md) + if err != nil { + return postSingleData{}, fmt.Errorf("failed to parse post %s: %w", post.Slug, err) + } + + for _, processor := range b.postMDProcessors { + if err := processor(b.site, dom); err != nil { + return postSingleData{}, fmt.Errorf("failed to process post %s: %w", post.Slug, err) + } + } + + outHTML, err := dom.Find("body").Html() + if err != nil { + return postSingleData{}, fmt.Errorf("failed to render post %s: %w", post.Slug, err) + } + md.Reset() + md.WriteString(outHTML) + } + postURL := strings.TrimSuffix(b.site.BaseURL, "/") + "/" + strings.TrimPrefix(postPath, "/") return postSingleData{ diff --git a/providers/sitebuilder/processors.go b/providers/sitebuilder/processors.go new file mode 100644 index 0000000..c699160 --- /dev/null +++ b/providers/sitebuilder/processors.go @@ -0,0 +1,37 @@ +package sitebuilder + +import ( + "net/url" + "strings" + + "github.com/PuerkitoBio/goquery" + "lmika.dev/lmika/weiro/models/pubmodel" +) + +type postMDProcessor func(site pubmodel.Site, dom *goquery.Document) error + +func uploadAbsoluteURL(site pubmodel.Site, dom *goquery.Document) error { + siteURL, err := url.Parse(site.BaseURL) + if err != nil { + return err + } + + dom.Find("img").Each(func(i int, s *goquery.Selection) { + srcUrl := s.AttrOr("src", "") + if site.BaseURL == "" { + return + } else if strings.HasPrefix(srcUrl, "http:") || strings.HasPrefix(srcUrl, "https:") { + return + } + + pu, err := url.Parse(srcUrl) + if err != nil { + return + } + + absURL := siteURL.ResolveReference(pu) + + s.SetAttr("src", absURL.String()) + }) + return nil +} diff --git a/providers/sitebuilder/tmplfns.go b/providers/sitebuilder/tmplfns.go index 4b69a57..c6adc58 100644 --- a/providers/sitebuilder/tmplfns.go +++ b/providers/sitebuilder/tmplfns.go @@ -3,7 +3,7 @@ package sitebuilder import ( "html/template" "net/url" - "path/filepath" + "strings" "time" "lmika.dev/lmika/weiro/models/pubmodel" @@ -20,7 +20,7 @@ func templateFns(site pubmodel.Site, opts Options) template.FuncMap { if err != nil { return "", err } - pu.Path = filepath.Join(pu.Path, basePath) + pu.Path = joinPath(pu.Path, basePath) return pu.String(), nil }, "format_date": func(date time.Time) string { @@ -32,3 +32,7 @@ func templateFns(site pubmodel.Site, opts Options) template.FuncMap { }, } } + +func joinPath(basePath, path string) string { + return strings.TrimSuffix(basePath, "/") + "/" + strings.TrimPrefix(path, "/") +}