diff --git a/plugin.go b/plugin.go index 46fd1a7..6d5b730 100644 --- a/plugin.go +++ b/plugin.go @@ -18,7 +18,7 @@ type Plugin interface { SetRoutes(group *echo.Group) // Inject is called prior to rendering a template. It can extend the // template data by setting new items in the Extra map. - Inject(name string, data interface{}) error + Inject(name string, data RenderData) error // Close is called when the plugin is unloaded. Close() error } diff --git a/plugin_go.go b/plugin_go.go index 43e9aea..407363c 100644 --- a/plugin_go.go +++ b/plugin_go.go @@ -40,7 +40,7 @@ func (p *goPlugin) SetRoutes(group *echo.Group) { group.Static("/plugins/"+p.p.Name+"/assets", pluginDir+"/"+p.p.Name+"/public/assets") } -func (p *goPlugin) Inject(name string, data interface{}) error { +func (p *goPlugin) Inject(name string, data RenderData) error { if f, ok := p.p.injectFuncs["*"]; ok { if err := f(data); err != nil { return err @@ -114,7 +114,7 @@ func (p *GoPlugin) TemplateFuncs(funcs template.FuncMap) { } // InjectFunc is a function that injects data prior to rendering a template. -type InjectFunc func(data interface{}) error +type InjectFunc func(data RenderData) error // Inject registers a function to execute prior to rendering a template. The // special name "*" matches any template. diff --git a/plugin_lua.go b/plugin_lua.go index 638f17c..816c7f1 100644 --- a/plugin_lua.go +++ b/plugin_lua.go @@ -68,7 +68,7 @@ func (p *luaPlugin) setRoute(l *lua.LState) int { return 0 } -func (p *luaPlugin) inject(name string, data interface{}) error { +func (p *luaPlugin) inject(name string, data RenderData) error { f, ok := p.renderCallbacks[name] if !ok { return nil @@ -86,7 +86,7 @@ func (p *luaPlugin) inject(name string, data interface{}) error { return nil } -func (p *luaPlugin) Inject(name string, data interface{}) error { +func (p *luaPlugin) Inject(name string, data RenderData) error { if err := p.inject("*", data); err != nil { return err } diff --git a/plugins/base/routes.go b/plugins/base/routes.go index fe3e946..f3f196a 100644 --- a/plugins/base/routes.go +++ b/plugins/base/routes.go @@ -116,12 +116,12 @@ func handleGetMailbox(ectx echo.Context) error { return ctx.Render(http.StatusOK, "mailbox.html", &MailboxRenderData{ BaseRenderData: *koushin.NewBaseRenderData(ctx), - Mailbox: mbox, - Mailboxes: mailboxes, - Messages: msgs, - PrevPage: prevPage, - NextPage: nextPage, - Query: query, + Mailbox: mbox, + Mailboxes: mailboxes, + Messages: msgs, + PrevPage: prevPage, + NextPage: nextPage, + Query: query, }) } @@ -239,14 +239,14 @@ func handleGetPart(ctx *koushin.Context, raw bool) error { } return ctx.Render(http.StatusOK, "message.html", &MessageRenderData{ - BaseRenderData: *koushin.NewBaseRenderData(ctx), - Mailboxes: mailboxes, - Mailbox: mbox, - Message: msg, - Body: body, - PartPath: partPathString, - MailboxPage: int(mbox.Messages-msg.SeqNum) / messagesPerPage, - Flags: flags, + BaseRenderData: *koushin.NewBaseRenderData(ctx), + Mailboxes: mailboxes, + Mailbox: mbox, + Message: msg, + Body: body, + PartPath: partPathString, + MailboxPage: int(mbox.Messages-msg.SeqNum) / messagesPerPage, + Flags: flags, }) } @@ -354,7 +354,7 @@ func handleCompose(ectx echo.Context) error { return ctx.Render(http.StatusOK, "compose.html", &ComposeRenderData{ BaseRenderData: *koushin.NewBaseRenderData(ctx), - Message: &msg, + Message: &msg, }) } diff --git a/template.go b/template.go index 379b6d5..6286e08 100644 --- a/template.go +++ b/template.go @@ -20,18 +20,48 @@ type GlobalRenderData struct { Username string // TODO: list of mailboxes - // Additional plugin-specific data + // additional plugin-specific data Extra map[string]interface{} } // BaseRenderData is the base type for templates. It should be extended with -// new template-specific fields. +// additional template-specific fields: +// +// type MyRenderData struct { +// BaseRenderData +// // add additional fields here +// } type BaseRenderData struct { - Global GlobalRenderData - // Additional plugin-specific data + GlobalData GlobalRenderData + // additional plugin-specific data Extra map[string]interface{} } +// Global implements RenderData. +func (brd *BaseRenderData) Global() *GlobalRenderData { + return &brd.GlobalData +} + +// RenderData is implemented by template data structs. It can be used to inject +// additional data to all templates. +type RenderData interface { + // GlobalData returns a pointer to the global render data. + Global() *GlobalRenderData +} + +// NewBaseRenderData initializes a new BaseRenderData. +// +// It can be used by routes to pre-fill the base data: +// +// type MyRenderData struct { +// BaseRenderData +// // add additional fields here +// } +// +// data := &MyRenderData{ +// BaseRenderData: *koushin.NewBaseRenderData(ctx), +// // other fields... +// } func NewBaseRenderData(ctx *Context) *BaseRenderData { global := GlobalRenderData{Extra: make(map[string]interface{})} @@ -41,8 +71,8 @@ func NewBaseRenderData(ctx *Context) *BaseRenderData { } return &BaseRenderData{ - Global: global, - Extra: make(map[string]interface{}), + GlobalData: global, + Extra: make(map[string]interface{}), } } @@ -57,7 +87,7 @@ func (r *renderer) Render(w io.Writer, name string, data interface{}, ectx echo. ctx := ectx.Get("context").(*Context) for _, plugin := range ctx.Server.Plugins { - if err := plugin.Inject(name, data); err != nil { + if err := plugin.Inject(name, data.(RenderData)); err != nil { return fmt.Errorf("failed to run plugin '%v': %v", plugin.Name(), err) } }