зеркало из https://github.com/golang/pkgsite.git
content/static,internal/frontend,internal/middleware: add 'y' keyboard shortcut to canonicalise URL with version
The address bar URL will be updated to be the canonical url of package. Canonical url includes the module version in address bar. Fixes golang/go#36807 Change-Id: I4a6f9737ff7e112ebf1d093b2eebe2af311fb0c6 Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/239179 Reviewed-by: Jamal Carvalho <jamal@golang.org> Reviewed-by: Andrew Bonventre <andybons@golang.org> Run-TryBot: Andrew Bonventre <andybons@golang.org> TryBot-Result: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Родитель
3bf54b6c75
Коммит
6440758d8a
|
@ -208,6 +208,7 @@
|
|||
{{end}}
|
||||
|
||||
{{define "post_content"}}
|
||||
<div class="js-canonicalURLPath" data-canonical-url-path="{{.CanonicalURLPath}}" hidden />
|
||||
<script>
|
||||
loadScript('/static/js/details.min.js');
|
||||
</script>
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file.
|
||||
*/
|
||||
var k="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};function l(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");}var n=l(this);
|
||||
function p(a,b){if(b)a:{var c=n;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&k(c,a,{configurable:!0,writable:!0,value:b})}}
|
||||
var k="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};function l(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");}var m=l(this);
|
||||
function p(a,b){if(b)a:{var c=m;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&k(c,a,{configurable:!0,writable:!0,value:b})}}
|
||||
p("Array.from",function(a){return a?a:function(b,c,d){c=null!=c?c:function(h){return h};var e=[],f="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];if("function"==typeof f){b=f.call(b);for(var g=0;!(f=b.next()).done;)e.push(c.call(d,f.value,g++))}else for(f=b.length,g=0;g<f;g++)e.push(c.call(d,b[g],g));return e}});p("Object.is",function(a){return a?a:function(b,c){return b===c?0!==b||1/b===1/c:b!==b&&c!==c}});
|
||||
p("Array.prototype.includes",function(a){return a?a:function(b,c){var d=this;d instanceof String&&(d=String(d));var e=d.length;c=c||0;for(0>c&&(c=Math.max(c+e,0));c<e;c++){var f=d[c];if(f===b||Object.is(f,b))return!0}return!1}});
|
||||
p("String.prototype.includes",function(a){return a?a:function(b,c){if(null==this)throw new TypeError("The 'this' value for String.prototype.includes must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype.includes must not be a regular expression");return-1!==this.indexOf(b,c||0)}});function q(a){var b=this;this.a=a;this.b=a.dataset.toCopy;a.addEventListener("click",function(c){return r(b,c)})}
|
||||
function r(a,b){b.preventDefault();navigator.clipboard?navigator.clipboard.writeText(a.b).then(function(){t(a,"Copied!")}).catch(function(){t(a,"Unable to copy")}):t(a,"Unable to copy")}function t(a,b){a.a.setAttribute("data-tooltip",b);setTimeout(function(){return a.a.setAttribute("data-tooltip","")},1E3)}function u(a,b){b.forEach(function(c){a.b.setAttribute("aria-hidden",c.isIntersecting)})}
|
||||
function v(a){var b=this;if(!a)throw Error("Must provide an element.");this.a=a;a=this.a.querySelector("select");if(!a)throw Error("Element must contain a <select> element.");this.b=a;this.c=[];if(window.ResizeObserver){var c=0;this.c=Array.from(this.a.querySelectorAll("[role='tab']")).map(function(d,e){0===e&&(c=d.offsetLeft);return d.offsetLeft+d.offsetWidth-c});(new ResizeObserver(function(d){return w(b,d)})).observe(this.a);this.b.addEventListener("change",function(d){window.location.href=d.target.value})}else this.a.style.overflowX=
|
||||
"scroll"}function w(a,b){b.forEach(function(c){var d=c.target.getBoundingClientRect(),e=[];a.a.querySelectorAll("[role='tab']").forEach(function(f,g){var h=a.c[g],m=d.width;a.a.classList.contains("is-overflowing")&&(m-=40);h=h>m;f.setAttribute("aria-hidden",h);h&&e.push(g)});a.a.classList.toggle("is-overflowing",0!==e.length);a.b.querySelectorAll("option").forEach(function(f,g){f.disabled=!e.includes(g)||"true"===f.getAttribute("data-always-disabled")})})}
|
||||
"scroll"}function w(a,b){b.forEach(function(c){var d=c.target.getBoundingClientRect(),e=[];a.a.querySelectorAll("[role='tab']").forEach(function(f,g){var h=a.c[g],n=d.width;a.a.classList.contains("is-overflowing")&&(n-=40);h=h>n;f.setAttribute("aria-hidden",h);h&&e.push(g)});a.a.classList.toggle("is-overflowing",0!==e.length);a.b.querySelectorAll("option").forEach(function(f,g){f.disabled=!e.includes(g)||"true"===f.getAttribute("data-always-disabled")})})}
|
||||
new function(){var a=document.querySelector(".js-fixedHeaderSentinel"),b=document.querySelector(".js-fixedHeader"),c=this;if(!a||!b)throw Error("Must provide sentinel and fixed elements to constructor.");this.a=a;this.b=b;this.c=new IntersectionObserver(function(d){return u(c,d)},{threshold:1});this.c.observe(this.a);void 0!==window.getComputedStyle(document.body)["-webkit-overflow-scrolling"]&&[document.documentElement,document.body].forEach(function(d){d.style.overflow="auto"})};document.querySelectorAll(".js-overflowingTabList").forEach(function(a){return new v(a)});
|
||||
document.querySelectorAll(".js-copyToClipboard").forEach(function(a){new q(a)});
|
||||
document.querySelectorAll(".js-copyToClipboard").forEach(function(a){new q(a)});var x=document.querySelector(".js-canonicalURLPath").dataset.canonicalUrlPath;x&&""!==x&&document.addEventListener("keydown",function(a){var b=a.target.tagName;if("INPUT"!==b&&"SELECT"!==b&&"TEXTAREA"!==b&&!a.target.isContentEditable&&!a.metaKey&&!a.ctrlKey)switch(a.key){case "y":window.history.replaceState(null,"",x)}});
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright 2019-2020 The Go Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style
|
||||
* license that can be found in the LICENSE file.
|
||||
*/
|
||||
|
||||
// This file implements the behavior of the keyboard shortcut which allows
|
||||
// for users to press 'y' to to change browser URL to the canonical URL
|
||||
// without triggering a reload.
|
||||
|
||||
const canonicalURLPath = document.querySelector('.js-canonicalURLPath').dataset['canonicalUrlPath'];
|
||||
if (canonicalURLPath && canonicalURLPath !== '') {
|
||||
document.addEventListener('keydown', e => {
|
||||
// TODO(golang.org/issue/40246): consolidate keyboard shortcut behavior across the site.
|
||||
const t = e.target.tagName;
|
||||
if (t === 'INPUT' || t === 'SELECT' || t === 'TEXTAREA') {
|
||||
return;
|
||||
}
|
||||
if (e.target.isContentEditable) {
|
||||
return;
|
||||
}
|
||||
if (e.metaKey || e.ctrlKey) {
|
||||
return;
|
||||
}
|
||||
switch (e.key) {
|
||||
case 'y':
|
||||
window.history.replaceState(null, '', canonicalURLPath);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
|
@ -45,7 +45,7 @@ main() {
|
|||
cmd=check
|
||||
fi
|
||||
$cmd $JSDIR/base.min.js $JSDIR/{site,analytics}.js
|
||||
$cmd $JSDIR/details.min.js -advanced $JSDIR/{clipboard,fixed_header,overflowing_tab_list,details}.js
|
||||
$cmd $JSDIR/details.min.js -advanced $JSDIR/{clipboard,fixed_header,overflowing_tab_list,details,keyboard}.js
|
||||
$cmd $JSDIR/fetch.min.js $JSDIR/fetch.js
|
||||
$cmd $JSDIR/playground.min.js $JSDIR/playground.js
|
||||
$cmd $JSDIR/badge.min.js $JSDIR/badge.js
|
||||
|
|
|
@ -55,6 +55,12 @@ type DetailsPage struct {
|
|||
|
||||
// Tabs contains data to render the varioius tabs on each details page.
|
||||
Tabs []TabSettings
|
||||
|
||||
// CanonicalURLPath is the representation of the URL path for the details
|
||||
// page, after the requested version and module path have been resolved.
|
||||
// For example, if the latest version of /my.module/pkg is version v1.5.2,
|
||||
// the canonical url for that path would be /my.module@v1.5.2/pkg
|
||||
CanonicalURLPath string
|
||||
}
|
||||
|
||||
const (
|
||||
|
|
|
@ -105,6 +105,11 @@ func (s *Server) legacyServeDirectoryPage(ctx context.Context, w http.ResponseWr
|
|||
CanShowDetails: true,
|
||||
Tabs: directoryTabSettings,
|
||||
PageType: pageTypeDirectory,
|
||||
CanonicalURLPath: constructPackageURL(
|
||||
dbDir.Path,
|
||||
dbDir.ModulePath,
|
||||
linkVersion(dbDir.Version, dbDir.ModulePath),
|
||||
),
|
||||
}
|
||||
s.servePage(ctx, w, settings.TemplateName, page)
|
||||
return nil
|
||||
|
|
|
@ -87,6 +87,10 @@ func (s *Server) serveModulePage(ctx context.Context, w http.ResponseWriter, r *
|
|||
CanShowDetails: canShowDetails,
|
||||
Tabs: moduleTabSettings,
|
||||
PageType: pageType,
|
||||
CanonicalURLPath: constructModuleURL(
|
||||
mi.ModulePath,
|
||||
linkVersion(mi.Version, mi.ModulePath),
|
||||
),
|
||||
}
|
||||
s.servePage(ctx, w, settings.TemplateName, page)
|
||||
return nil
|
||||
|
|
|
@ -138,6 +138,11 @@ func (s *Server) legacyServePackagePageWithPackage(w http.ResponseWriter, r *htt
|
|||
CanShowDetails: canShowDetails,
|
||||
Tabs: packageTabSettings,
|
||||
PageType: pageType,
|
||||
CanonicalURLPath: constructPackageURL(
|
||||
pkg.Path,
|
||||
pkg.ModulePath,
|
||||
linkVersion(pkg.Version, pkg.ModulePath),
|
||||
),
|
||||
}
|
||||
s.servePage(r.Context(), w, settings.TemplateName, page)
|
||||
return nil
|
||||
|
|
Загрузка…
Ссылка в новой задаче