Add RenderData interface
This allows Go plugins to easily inject global data.
This commit is contained in:
parent
d8a875a5f7
commit
ca3672df2a
5 changed files with 57 additions and 27 deletions
|
@ -18,7 +18,7 @@ type Plugin interface {
|
||||||
SetRoutes(group *echo.Group)
|
SetRoutes(group *echo.Group)
|
||||||
// Inject is called prior to rendering a template. It can extend the
|
// Inject is called prior to rendering a template. It can extend the
|
||||||
// template data by setting new items in the Extra map.
|
// 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 is called when the plugin is unloaded.
|
||||||
Close() error
|
Close() error
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ func (p *goPlugin) SetRoutes(group *echo.Group) {
|
||||||
group.Static("/plugins/"+p.p.Name+"/assets", pluginDir+"/"+p.p.Name+"/public/assets")
|
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 f, ok := p.p.injectFuncs["*"]; ok {
|
||||||
if err := f(data); err != nil {
|
if err := f(data); err != nil {
|
||||||
return err
|
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.
|
// 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
|
// Inject registers a function to execute prior to rendering a template. The
|
||||||
// special name "*" matches any template.
|
// special name "*" matches any template.
|
||||||
|
|
|
@ -68,7 +68,7 @@ func (p *luaPlugin) setRoute(l *lua.LState) int {
|
||||||
return 0
|
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]
|
f, ok := p.renderCallbacks[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
@ -86,7 +86,7 @@ func (p *luaPlugin) inject(name string, data interface{}) error {
|
||||||
return nil
|
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 {
|
if err := p.inject("*", data); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,12 +116,12 @@ func handleGetMailbox(ectx echo.Context) error {
|
||||||
|
|
||||||
return ctx.Render(http.StatusOK, "mailbox.html", &MailboxRenderData{
|
return ctx.Render(http.StatusOK, "mailbox.html", &MailboxRenderData{
|
||||||
BaseRenderData: *koushin.NewBaseRenderData(ctx),
|
BaseRenderData: *koushin.NewBaseRenderData(ctx),
|
||||||
Mailbox: mbox,
|
Mailbox: mbox,
|
||||||
Mailboxes: mailboxes,
|
Mailboxes: mailboxes,
|
||||||
Messages: msgs,
|
Messages: msgs,
|
||||||
PrevPage: prevPage,
|
PrevPage: prevPage,
|
||||||
NextPage: nextPage,
|
NextPage: nextPage,
|
||||||
Query: query,
|
Query: query,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,14 +239,14 @@ func handleGetPart(ctx *koushin.Context, raw bool) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
return ctx.Render(http.StatusOK, "message.html", &MessageRenderData{
|
return ctx.Render(http.StatusOK, "message.html", &MessageRenderData{
|
||||||
BaseRenderData: *koushin.NewBaseRenderData(ctx),
|
BaseRenderData: *koushin.NewBaseRenderData(ctx),
|
||||||
Mailboxes: mailboxes,
|
Mailboxes: mailboxes,
|
||||||
Mailbox: mbox,
|
Mailbox: mbox,
|
||||||
Message: msg,
|
Message: msg,
|
||||||
Body: body,
|
Body: body,
|
||||||
PartPath: partPathString,
|
PartPath: partPathString,
|
||||||
MailboxPage: int(mbox.Messages-msg.SeqNum) / messagesPerPage,
|
MailboxPage: int(mbox.Messages-msg.SeqNum) / messagesPerPage,
|
||||||
Flags: flags,
|
Flags: flags,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,7 +354,7 @@ func handleCompose(ectx echo.Context) error {
|
||||||
|
|
||||||
return ctx.Render(http.StatusOK, "compose.html", &ComposeRenderData{
|
return ctx.Render(http.StatusOK, "compose.html", &ComposeRenderData{
|
||||||
BaseRenderData: *koushin.NewBaseRenderData(ctx),
|
BaseRenderData: *koushin.NewBaseRenderData(ctx),
|
||||||
Message: &msg,
|
Message: &msg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
44
template.go
44
template.go
|
@ -20,18 +20,48 @@ type GlobalRenderData struct {
|
||||||
Username string
|
Username string
|
||||||
// TODO: list of mailboxes
|
// TODO: list of mailboxes
|
||||||
|
|
||||||
// Additional plugin-specific data
|
// additional plugin-specific data
|
||||||
Extra map[string]interface{}
|
Extra map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseRenderData is the base type for templates. It should be extended with
|
// 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 {
|
type BaseRenderData struct {
|
||||||
Global GlobalRenderData
|
GlobalData GlobalRenderData
|
||||||
// Additional plugin-specific data
|
// additional plugin-specific data
|
||||||
Extra map[string]interface{}
|
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 {
|
func NewBaseRenderData(ctx *Context) *BaseRenderData {
|
||||||
global := GlobalRenderData{Extra: make(map[string]interface{})}
|
global := GlobalRenderData{Extra: make(map[string]interface{})}
|
||||||
|
|
||||||
|
@ -41,8 +71,8 @@ func NewBaseRenderData(ctx *Context) *BaseRenderData {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &BaseRenderData{
|
return &BaseRenderData{
|
||||||
Global: global,
|
GlobalData: global,
|
||||||
Extra: make(map[string]interface{}),
|
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)
|
ctx := ectx.Get("context").(*Context)
|
||||||
|
|
||||||
for _, plugin := range ctx.Server.Plugins {
|
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)
|
return fmt.Errorf("failed to run plugin '%v': %v", plugin.Name(), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue