123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114 |
- // The Isomorphic Go Project
- // Copyright (c) Wirecog, LLC. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license, which can be found in the LICENSE file.
-
- package isokit
-
- import (
- "context"
- "strings"
-
- "github.com/gopherjs/gopherjs/js"
- "honnef.co/go/js/dom"
- )
-
- type Router struct {
- routes []*Route
- listener func(*js.Object)
- }
-
- func NewRouter() *Router {
-
- initializeHistoryInteractions()
-
- return &Router{
- routes: []*Route{},
- }
- }
-
- func (r *Router) Handle(path string, handler Handler) *Route {
- return r.HandleFunc(path, handler.(HandlerFunc))
- }
-
- func (r *Router) HandleFunc(path string, handler HandlerFunc) *Route {
- route := NewRoute(path, handler)
- r.routes = append(r.routes, route)
- return route
- }
-
- func (r *Router) Listen() {
- r.RegisterLinks("body a")
- }
-
- func (r *Router) RegisterLinks(querySelector string) {
- document := dom.GetWindow().Document().(dom.HTMLDocument)
- links := document.QuerySelectorAll(querySelector)
-
- for _, link := range links {
-
- href := link.GetAttribute("href")
- switch {
-
- case strings.HasPrefix(href, "/") && !strings.HasPrefix(href, "//"):
-
- if r.listener != nil {
- link.RemoveEventListener("click", false, r.listener)
- }
-
- r.listener = link.AddEventListener("click", false, r.linkHandler)
- }
- }
-
- }
-
- func (r *Router) linkHandler(event dom.Event) {
-
- uri := event.CurrentTarget().GetAttribute("href")
- path := strings.Split(uri, "?")[0]
- // leastParams := -1
- var matchedRoute *Route
- var parts []string
- var lowestMatchCountSet bool = false
- var lowestMatchCount int = -1
-
- for _, route := range r.routes {
-
- matches := route.regex.FindStringSubmatch(path)
- matchesExist := len(matches) > 0 && matches != nil
- isLowestMatchCount := (lowestMatchCountSet == false) || (len(matches) < lowestMatchCount)
-
- if matchesExist && isLowestMatchCount {
- matchedRoute = route
- parts = matches[1:]
- lowestMatchCount = len(matches)
- lowestMatchCountSet = true
- }
- }
-
- if matchedRoute != nil {
- event.PreventDefault()
- js.Global.Get("history").Call("pushState", nil, "", uri)
- routeVars := make(map[string]string)
-
- for i, part := range parts {
- routeVars[matchedRoute.varNames[i]+`}`] = part
- }
-
- var ctx context.Context
- ctx, cancel := context.WithCancel(context.Background())
- defer cancel()
-
- k := RouteVarsKey("Vars")
- ctx = context.WithValue(ctx, k, routeVars)
- go matchedRoute.handler.ServeRoute(ctx)
- }
- }
-
- func initializeHistoryInteractions() {
- // Handler for back/forward button interactions
- dom.GetWindow().AddEventListener("popstate", false, func(event dom.Event) {
- var location = js.Global.Get("location")
- js.Global.Set("location", location)
- })
- }
|