gddo-server: add UI to turn on/off redirect to pkg.go.dev This change adds UI for the option to set a cookie and have candidate godoc.org links redirect to their equivalent pkg.go.dev counterparts. If a user returns to godoc.org with the utm_source form value equal to 'backtogodoc', it will display an option to turn off the automatic redirect. The intention is to have a link on pkg.go.dev that allows the user to return to godoc.org and also turn off the automatic redirect without having to know the special URL param values. Updates golang/go#37099 Change-Id: I27bd03cbc484a1e504795ff669224c2a2a7d72b6 Reviewed-on: https://go-review.googlesource.com/c/gddo/+/222315 Reviewed-by: Jonathan Amsterdam <jba@google.com> Reviewed-by: Alexander Rakoczy <alex@golang.org>
diff --git a/gddo-server/assets/site.css b/gddo-server/assets/site.css index 71da77f..f05feb4 100644 --- a/gddo-server/assets/site.css +++ b/gddo-server/assets/site.css
@@ -123,12 +123,17 @@ .banner-action-container { text-align: right; + white-space: nowrap; } .banner-action { white-space: nowrap; } +.banner-action + .banner-action { + margin-left: 24px; +} + @media (max-width: 768px) { .banner { flex-direction: column; @@ -180,3 +185,42 @@ text-transform: uppercase; font-size: 0.75em; } + +.redirect-toast { + align-items: center; + background-color: #202124; + border-radius: 4px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); + bottom: 20px; + color: #fff; + display: flex; + justify-content: space-between; + left: 20px; + padding: 10px 18px; + position: fixed; +} + +@media (max-width: 768px) { + .redirect-toast { + width: calc(100% - 40px); + } +} + +.redirect-toast-actions { + margin-left: 48px; + white-space: nowrap; +} + +.redirect-toast-action, +.redirect-toast-action:link, +.redirect-toast-action:visited { + background: none; + border: 0; + color: #8ab4f9; + padding: 10px; +} + +.redirect-toast-action:active, +.redirect-toast-action:hover { + text-decoration: none; +}
diff --git a/gddo-server/assets/site.js b/gddo-server/assets/site.js index 4f52d58..04e26c3 100644 --- a/gddo-server/assets/site.js +++ b/gddo-server/assets/site.js
@@ -103,11 +103,11 @@ switch(e.which) { case 38: // up incrActive(-1); - e.preventDefault(); + e.preventDefault(); break; case 40: // down incrActive(1); - e.preventDefault(); + e.preventDefault(); break; case 13: // enter if (active >= 0) { @@ -228,4 +228,14 @@ target: '.gddo-sidebar', offset: 10 }); + + const redirectToastEl = document.querySelector('.js-redirectToast'); + if (!redirectToastEl) { + return; // element may not even be on the page + } + const redirectToastDismissEl = redirectToastEl.querySelector('.js-redirectToastDismiss'); + redirectToastDismissEl.addEventListener('click', e => { + e.preventDefault(); + redirectToastEl.style.display = 'none'; + }); });
diff --git a/gddo-server/assets/templates/layout.html b/gddo-server/assets/templates/layout.html index 577203a..4bd077a 100644 --- a/gddo-server/assets/templates/layout.html +++ b/gddo-server/assets/templates/layout.html
@@ -32,6 +32,7 @@ Pkg.go.dev is a new destination for Go discovery & docs. Check it out at {{template "PkgGoDevLink" $}} and share your feedback. </div> <div class="banner-action-container"> + <a class="banner-action" href="?redirect=on">Always use pkg.go.dev</a> <a class="banner-action" href="https://blog.golang.org/pkg.go.dev-2020">Learn more</a> </div> </div> @@ -71,6 +72,16 @@ </div> </div> </div> + +{{if .showPkgGoDevRedirectToast}} + <div class="redirect-toast js-redirectToast"> + <div>Always use godoc.org as default</div> + <div class="redirect-toast-actions"> + <a class="redirect-toast-action" href="?redirect=off">Yes</a> + <button class="redirect-toast-action js-redirectToastDismiss">Dismiss</button> + </div> + </div> +{{end}} <script src="{{staticPath "/-/jquery-2.0.3.min.js"}}"></script> <script src="{{staticPath "/-/bootstrap.min.js"}}"></script> <script src="{{staticPath "/-/site.js"}}"></script>
diff --git a/gddo-server/main.go b/gddo-server/main.go index f3df330..795df07 100644 --- a/gddo-server/main.go +++ b/gddo-server/main.go
@@ -274,6 +274,8 @@ } } + showPkgGoDevRedirectToast := userReturningFromPkgGoDev(req) + switch { case isView(req, "imports"): if pdoc.Name == "" { @@ -284,9 +286,10 @@ return err } return s.templates.execute(resp, "imports.html", http.StatusOK, nil, map[string]interface{}{ - "flashMessages": flashMessages, - "pkgs": pkgs, - "pdoc": newTDoc(s.v, pdoc), + "flashMessages": flashMessages, + "pkgs": pkgs, + "pdoc": newTDoc(s.v, pdoc), + "showPkgGoDevRedirectToast": showPkgGoDevRedirectToast, }) case isView(req, "tools"): proto := "http" @@ -294,9 +297,10 @@ proto = "https" } return s.templates.execute(resp, "tools.html", http.StatusOK, nil, map[string]interface{}{ - "flashMessages": flashMessages, - "uri": fmt.Sprintf("%s://%s/%s", proto, req.Host, importPath), - "pdoc": newTDoc(s.v, pdoc), + "flashMessages": flashMessages, + "uri": fmt.Sprintf("%s://%s/%s", proto, req.Host, importPath), + "pdoc": newTDoc(s.v, pdoc), + "showPkgGoDevRedirectToast": showPkgGoDevRedirectToast, }) case isView(req, "importers"): if pdoc.Name == "" { @@ -312,9 +316,10 @@ template = "importers_robot.html" } return s.templates.execute(resp, template, http.StatusOK, nil, map[string]interface{}{ - "flashMessages": flashMessages, - "pkgs": pkgs, - "pdoc": newTDoc(s.v, pdoc), + "flashMessages": flashMessages, + "pkgs": pkgs, + "pdoc": newTDoc(s.v, pdoc), + "showPkgGoDevRedirectToast": showPkgGoDevRedirectToast, }) case isView(req, "import-graph"): if requestType == robotRequest { @@ -339,10 +344,11 @@ return err } return s.templates.execute(resp, "graph.html", http.StatusOK, nil, map[string]interface{}{ - "flashMessages": flashMessages, - "svg": template.HTML(b), - "pdoc": newTDoc(s.v, pdoc), - "hide": hide, + "flashMessages": flashMessages, + "svg": template.HTML(b), + "pdoc": newTDoc(s.v, pdoc), + "hide": hide, + "showPkgGoDevRedirectToast": showPkgGoDevRedirectToast, }) case isView(req, "play"): u, err := s.playURL(pdoc, req.Form.Get("play"), req.Header.Get("X-AppEngine-Country")) @@ -410,10 +416,11 @@ template += templateExt(req) return s.templates.execute(resp, template, status, http.Header{"Etag": {etag}}, map[string]interface{}{ - "flashMessages": flashMessages, - "pkgs": pkgs, - "pdoc": newTDoc(s.v, pdoc), - "importerCount": importerCount, + "flashMessages": flashMessages, + "pkgs": pkgs, + "pdoc": newTDoc(s.v, pdoc), + "importerCount": importerCount, + "showPkgGoDevRedirectToast": showPkgGoDevRedirectToast, }) } } @@ -544,7 +551,11 @@ } return s.templates.execute(resp, "home"+templateExt(req), http.StatusOK, nil, - map[string]interface{}{"Popular": pkgs}) + map[string]interface{}{ + "Popular": pkgs, + + "showPkgGoDevRedirectToast": userReturningFromPkgGoDev(req), + }) } if path, ok := isBrowseURL(q); ok { @@ -577,12 +588,21 @@ } return s.templates.execute(resp, "results"+templateExt(req), http.StatusOK, nil, - map[string]interface{}{"q": q, "pkgs": pkgs}) + map[string]interface{}{ + "q": q, + "pkgs": pkgs, + + "showPkgGoDevRedirectToast": userReturningFromPkgGoDev(req), + }) } func (s *server) serveAbout(resp http.ResponseWriter, req *http.Request) error { return s.templates.execute(resp, "about.html", http.StatusOK, nil, - map[string]interface{}{"Host": req.Host}) + map[string]interface{}{ + "Host": req.Host, + + "showPkgGoDevRedirectToast": userReturningFromPkgGoDev(req), + }) } func (s *server) serveBot(resp http.ResponseWriter, req *http.Request) error { @@ -1071,6 +1091,10 @@ }) } +func userReturningFromPkgGoDev(req *http.Request) bool { + return req.FormValue("utm_source") == "backtogodoc" +} + var gddoToPkgGoDevRequest = map[string]string{ "/-/about": "/about", "/-/go": "/std", @@ -1083,6 +1107,10 @@ // if not redirecting to the same path that was used for the godoc.org request. func pkgGoDevRedirectHandler(f func(http.ResponseWriter, *http.Request) error) func(http.ResponseWriter, *http.Request) error { return func(w http.ResponseWriter, r *http.Request) error { + if userReturningFromPkgGoDev(r) { + return f(w, r) + } + redirectParam := r.FormValue(pkgGoDevRedirectParam) if redirectParam == pkgGoDevRedirectOn {
diff --git a/gddo-server/main_test.go b/gddo-server/main_test.go index ba76b64..269030a 100644 --- a/gddo-server/main_test.go +++ b/gddo-server/main_test.go
@@ -85,6 +85,12 @@ wantSetCookieHeader: "", wantStatusCode: http.StatusFound, }, + { + name: "do not redirect if user is returning from pkg.go.dev", + url: "http://godoc.org/net/http?utm_source=backtogodoc", + cookie: &http.Cookie{Name: "pkggodev-redirect", Value: "on"}, + wantStatusCode: http.StatusOK, + }, } { t.Run(test.name, func(t *testing.T) { req := httptest.NewRequest("GET", test.url, nil) @@ -108,7 +114,7 @@ } if got, want := resp.StatusCode, test.wantStatusCode; got != want { - t.Errorf("Status code mismatch: got %q; want %q", got, want) + t.Errorf("Status code mismatch: got %d; want %d", got, want) } }) }