api.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. package web
  2. import (
  3. "context"
  4. "net/http"
  5. "net/url"
  6. "strconv"
  7. "strings"
  8. "github.com/go-playground/form"
  9. "github.com/sunfmin/reflectutils"
  10. h "github.com/theplant/htmlgo"
  11. )
  12. type PageResponse struct {
  13. PageTitle string
  14. Body h.HTMLComponent
  15. }
  16. type PortalUpdate struct {
  17. Name string `json:"name,omitempty"`
  18. Body h.HTMLComponent `json:"body,omitempty"`
  19. }
  20. // @snippet_begin(EventResponseDefinition)
  21. type EventResponse struct {
  22. PageTitle string `json:"pageTitle,omitempty"`
  23. Body h.HTMLComponent `json:"body,omitempty"`
  24. Reload bool `json:"reload,omitempty"`
  25. PushState *LocationBuilder `json:"pushState"` // This we don't omitempty, So that {} can be kept when use url.Values{}
  26. RedirectURL string `json:"redirectURL,omitempty"` // change window url without push state
  27. ReloadPortals []string `json:"reloadPortals,omitempty"`
  28. UpdatePortals []*PortalUpdate `json:"updatePortals,omitempty"`
  29. Data interface{} `json:"data,omitempty"` // used for return collection data like TagsInput data source
  30. VarsScript string `json:"varsScript,omitempty"` // used with InitContextVars to set values for example vars.show to used by v-model
  31. }
  32. // @snippet_end
  33. // @snippet_begin(PageFuncAndEventFuncDefinition)
  34. type PageFunc func(ctx *EventContext) (r PageResponse, err error)
  35. type EventFunc func(ctx *EventContext) (r EventResponse, err error)
  36. // @snippet_end
  37. type LayoutFunc func(r *http.Request, injector *PageInjector, body string) (output string, err error)
  38. // @snippet_begin(EventFuncHubDefinition)
  39. type EventFuncHub interface {
  40. RegisterEventFunc(eventFuncId string, ef EventFunc) (key string)
  41. }
  42. // @snippet_end
  43. func AppendVarsScripts(er *EventResponse, scripts ...string) {
  44. if er.VarsScript != "" {
  45. scripts = append([]string{er.VarsScript}, scripts...)
  46. }
  47. er.VarsScript = strings.Join(scripts, "; ")
  48. }
  49. type EventFuncID struct {
  50. ID string `json:"id,omitempty"`
  51. }
  52. type EventContext struct {
  53. R *http.Request
  54. W http.ResponseWriter
  55. Injector *PageInjector
  56. Flash interface{} // pass value from actions to index
  57. }
  58. func (e *EventContext) QueryAsInt(key string) (r int) {
  59. strVal := e.R.FormValue(key)
  60. if len(strVal) == 0 {
  61. return
  62. }
  63. val, _ := strconv.ParseInt(strVal, 10, 64)
  64. r = int(val)
  65. return
  66. }
  67. func (e *EventContext) Queries() (r url.Values) {
  68. r = e.R.URL.Query()
  69. delete(r, EventFuncIDName)
  70. return
  71. }
  72. func (ctx *EventContext) MustUnmarshalForm(v interface{}) {
  73. err := ctx.UnmarshalForm(v)
  74. if err != nil {
  75. panic(err)
  76. }
  77. }
  78. func (ctx *EventContext) UnmarshalForm(v interface{}) (err error) {
  79. mf := ctx.R.MultipartForm
  80. if ctx.R.MultipartForm == nil {
  81. return
  82. }
  83. dec := form.NewDecoder()
  84. err = dec.Decode(v, mf.Value)
  85. if err != nil {
  86. // panic(err)
  87. return
  88. }
  89. if len(mf.File) > 0 {
  90. for k, vs := range mf.File {
  91. _ = reflectutils.Set(v, k, vs)
  92. }
  93. }
  94. return
  95. }
  96. type contextKey int
  97. const eventKey contextKey = iota
  98. func WrapEventContext(parent context.Context, ctx *EventContext) (r context.Context) {
  99. r = context.WithValue(parent, eventKey, ctx)
  100. return
  101. }
  102. func MustGetEventContext(c context.Context) (r *EventContext) {
  103. r, _ = c.Value(eventKey).(*EventContext)
  104. if r == nil {
  105. panic("EventContext required")
  106. }
  107. return
  108. }
  109. func Injector(c context.Context) (r *PageInjector) {
  110. ctx := MustGetEventContext(c)
  111. r = ctx.Injector
  112. return
  113. }