Common isomorphic functionality in one kit.

router.go 2.2KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // The Isomorphic Go Project
  2. // Copyright (c) Wirecog, LLC. All rights reserved.
  3. // Use of this source code is governed by a BSD-style
  4. // license, which can be found in the LICENSE file.
  5. package isokit
  6. import (
  7. "context"
  8. "strings"
  9. "github.com/gopherjs/gopherjs/js"
  10. "honnef.co/go/js/dom"
  11. )
  12. type Router struct {
  13. routes []*Route
  14. listener func(*js.Object)
  15. }
  16. func NewRouter() *Router {
  17. return &Router{
  18. routes: []*Route{},
  19. }
  20. }
  21. func (r *Router) Handle(path string, handler Handler) *Route {
  22. return r.HandleFunc(path, handler.(HandlerFunc))
  23. }
  24. func (r *Router) HandleFunc(path string, handler HandlerFunc) *Route {
  25. route := NewRoute(path, handler)
  26. r.routes = append(r.routes, route)
  27. return route
  28. }
  29. func (r *Router) Listen() {
  30. r.RegisterLinks()
  31. }
  32. func (r *Router) RegisterLinks() {
  33. document := dom.GetWindow().Document().(dom.HTMLDocument)
  34. for _, link := range document.Links() {
  35. href := link.GetAttribute("href")
  36. switch {
  37. case strings.HasPrefix(href, "/") && !strings.HasPrefix(href, "//"):
  38. if r.listener != nil {
  39. link.RemoveEventListener("click", true, r.listener)
  40. }
  41. r.listener = link.AddEventListener("click", true, r.linkHandler)
  42. }
  43. }
  44. }
  45. func (r *Router) linkHandler(event dom.Event) {
  46. uri := event.CurrentTarget().GetAttribute("href")
  47. path := strings.Split(uri, "?")[0]
  48. // leastParams := -1
  49. var matchedRoute *Route
  50. var parts []string
  51. var lowestMatchCountSet bool = false
  52. var lowestMatchCount int = -1
  53. for _, route := range r.routes {
  54. matches := route.regex.FindStringSubmatch(path)
  55. matchesExist := len(matches) > 0 && matches != nil
  56. isLowestMatchCount := (lowestMatchCountSet == false) || (len(matches) < lowestMatchCount)
  57. if matchesExist && isLowestMatchCount {
  58. matchedRoute = route
  59. parts = matches[1:]
  60. lowestMatchCount = len(matches)
  61. lowestMatchCountSet = true
  62. }
  63. }
  64. if matchedRoute != nil {
  65. event.PreventDefault()
  66. js.Global.Get("history").Call("pushState", nil, "", uri)
  67. routeVars := make(map[string]string)
  68. for i, part := range parts {
  69. routeVars[matchedRoute.varNames[i]] = part
  70. }
  71. var ctx context.Context
  72. ctx, cancel := context.WithCancel(context.Background())
  73. defer cancel()
  74. k := RouteVarsKey("Vars")
  75. ctx = context.WithValue(ctx, k, routeVars)
  76. go matchedRoute.handler.ServeRoute(ctx)
  77. }
  78. }