content: update frontend fetch UI
The frontend fetch UI is updated with a styled button, and loading dots
to indicate that a fetch request is in progress.
The Fetch API is now used instead of AJAX to make requests.
Updates golang/go#36811
Updates golang/go#37002
Change-Id: Ia37113dd9976f8e147875371c099f7b2bfd4bd85
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/240459
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/content/static/css/stylesheet.css b/content/static/css/stylesheet.css
index 300c415..6647a3f 100644
--- a/content/static/css/stylesheet.css
+++ b/content/static/css/stylesheet.css
@@ -516,6 +516,69 @@
position: absolute;
top: 62rem;
}
+
+.Error-gopher,
+.EmptyContent-gopher,
+.Fetch-gopher,
+.SearchResults-emptyContentGopher {
+ display: block;
+ margin: auto;
+ padding: 1.25rem 0;
+ max-width: 15rem;
+}
+.Error-message,
+.EmptyContent-message,
+.SearchResults-emptyContentMessage {
+ text-align: center;
+}
+.Fetch-container {
+ align-items: center;
+ display: flex;
+ flex-flow: column;
+}
+@keyframes blink {
+ 0% {
+ opacity: 0.2;
+ }
+ 20% {
+ opacity: 1;
+ }
+ 100% {
+ opacity: 0.2;
+ }
+}
+.Fetch-loading {
+ display: none;
+}
+.Fetch-dot {
+ animation-duration: 1.4s;
+ animation-fill-mode: both;
+ animation-iteration-count: infinite;
+ animation-name: blink;
+ background-color: var(--turq-dark);
+ border-radius: 50%;
+ display: inline-block;
+ height: 0.5rem;
+ width: 0.5rem;
+}
+.Fetch-loading:nth-child(2) {
+ animation-delay: 0.2s;
+}
+.Fetch-loading:nth-child(3) {
+ animation-delay: 0.4s;
+}
+.Fetch-button {
+ background-color: var(--gray-10);
+ border-radius: 0.5rem;
+ border: 0.0625rem solid var(--gray-8);
+ color: var(--turq-dark);
+ font-size: 1rem;
+ height: 2.5rem;
+ margin: 1rem 0;
+ padding: 0rem 1rem;
+ width: 5rem;
+}
+
.SearchResults {
margin: 0 auto;
max-width: 60em;
diff --git a/content/static/html/pages/fetch.tmpl b/content/static/html/pages/fetch.tmpl
new file mode 100644
index 0000000..d944d45
--- /dev/null
+++ b/content/static/html/pages/fetch.tmpl
@@ -0,0 +1,33 @@
+<!--
+ Copyright 2019 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.
+-->
+
+{{define "main_content"}}
+<div class="Container">
+ <div class="Content">
+ <div class="Fetch-container">
+ <img class="Fetch-gopher" src="/static/img/gopher-airplane.svg" alt="The Go Gopher">
+ <h3 class="Fetch-message js-fetchMessage" aria-live="polite" data-path="{{.MessageData}}">
+ Oops! {{.MessageData}} does not exist.
+ </h3>
+ <div class="Fetch-loading js-fetchLoading" aria-live="polite">
+ <i class="Fetch-dot"></i>
+ <i class="Fetch-dot"></i>
+ <i class="Fetch-dot"></i>
+ </div>
+ <p class="Fetch-messageSecondary js-fetchMessageSecondary" aria-live="polite">
+ Check that you entered it correctly, or request to fetch it.
+ </p>
+ <button class="Fetch-button js-fetchButton" aria-live="polite">Fetch</button>
+ </div>
+ </div>
+</div>
+{{end}}
+
+{{define "post_content"}}
+<script>
+ loadScript("/static/js/fetch.min.js");
+</script>
+{{end}}
diff --git a/content/static/html/pages/notfound.tmpl b/content/static/html/pages/notfound.tmpl
deleted file mode 100644
index b51399b..0000000
--- a/content/static/html/pages/notfound.tmpl
+++ /dev/null
@@ -1,57 +0,0 @@
-<!--
- Copyright 2019 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.
--->
-
-{{define "main_content"}}
-<div class="Container">
- <div class="Content">
- <img class="NotFound-gopher" src="/static/img/gopher-airplane.svg" alt="The Go Gopher">
- {{template "message" .MessageData}}
- <div class="NotFound-container">
- <button class="NotFound-button js-notFoundButton">Fetch</button>
- </div>
- </div>
-</div>
-
-<!-- TODO: update middleware.AcceptMethods so that the GET at the end of the
- script can be a POST instead.
- Do not add comments to the script below: they are stripped by html/template
- (https://golang.org/issue/28628), which messes up the CSP hash.
--->
-<script>
-const fetchButton = document.querySelector('.js-notFoundButton');
-if (fetchButton) {
- fetchButton.addEventListener('click', e => {
- e.preventDefault();
- fetchPath()
- });
-}
-function fetchPath() {
- httpRequest = new XMLHttpRequest();
- var btn = document.querySelector('.js-notFoundButton');
- btn.disabled = true;
- btn.className = 'NotFound-button-disabled';
-
- if (!httpRequest) {
- alert('Giving up :( Cannot create an XMLHTTP instance');
- return false;
- }
- httpRequest.onreadystatechange = function(){
- if (httpRequest.readyState === XMLHttpRequest.DONE) {
- if (httpRequest.status === 200) {
- location.reload();
- } else {
- document.querySelector('.js-notFoundMessage').innerHTML = httpRequest.responseText;
- btn.innerHTML = 'Failed';
- }
- }
- };
- document.querySelector('.js-notFoundMessage').innerHTML = "Fetching... Feel free to navigate away and check back later, we'll keep working on it!";
- btn.innerHTML = "Fetching...";
- httpRequest.open('GET', "/fetch" + window.location.pathname);
- httpRequest.send();
-}
-</script>
-{{end}}
diff --git a/content/static/js/fetch.js b/content/static/js/fetch.js
new file mode 100644
index 0000000..a6a9d45
--- /dev/null
+++ b/content/static/js/fetch.js
@@ -0,0 +1,33 @@
+/**
+ * @license
+ * Copyright 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.
+ */
+
+const fetchButton = document.querySelector('.js-fetchButton');
+if (fetchButton) {
+ fetchButton.addEventListener('click', e => {
+ e.preventDefault();
+ fetchPath();
+ });
+}
+
+async function fetchPath() {
+ const fetchMessageEl = document.querySelector('.js-fetchMessage');
+ fetchMessageEl.textContent = `Fetching ${fetchMessageEl.dataset.path}`;
+ document.querySelector('.js-fetchMessageSecondary').textContent =
+ "Feel free to navigate away and check back later, we’ll keep working on it!";
+ document.querySelector('.js-fetchButton').style.display = 'none';
+ document.querySelector('.js-fetchLoading').style.display = 'block';
+
+ const response = await fetch(`/fetch${window.location.pathname}`);
+ if (response.ok) {
+ window.location.reload();
+ return;
+ }
+ const responseText = await response.text();
+ document.querySelector('.js-fetchLoading').style.display = 'none';
+ document.querySelector('.js-fetchMessageSecondary').textContent = '';
+ document.querySelector('.js-fetchMessage').textContent = responseText;
+}
diff --git a/content/static/js/fetch.min.js b/content/static/js/fetch.min.js
new file mode 100644
index 0000000..35ab3c0
--- /dev/null
+++ b/content/static/js/fetch.min.js
@@ -0,0 +1,37 @@
+/*
+
+ Copyright 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.
+*/
+var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}};$jscomp.arrayIterator=function(a){return{next:$jscomp.arrayIteratorImpl(a)}};$jscomp.makeIterator=function(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):$jscomp.arrayIterator(a)};
+$jscomp.getGlobal=function(a){a=["object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global,a];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}return globalThis};$jscomp.global=$jscomp.getGlobal(this);$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;
+$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)};$jscomp.polyfill=function(a,b,c,d){if(b){c=$jscomp.global;a=a.split(".");for(d=0;d<a.length-1;d++){var e=a[d];e in c||(c[e]={});c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&$jscomp.defineProperty(c,a,{configurable:!0,writable:!0,value:b})}};$jscomp.FORCE_POLYFILL_PROMISE=!1;
+$jscomp.polyfill("Promise",function(a){function b(){this.batch_=null}function c(a){return a instanceof e?a:new e(function(b,f){b(a)})}if(a&&!$jscomp.FORCE_POLYFILL_PROMISE)return a;b.prototype.asyncExecute=function(a){if(null==this.batch_){this.batch_=[];var b=this;this.asyncExecuteFunction(function(){b.executeBatch_()})}this.batch_.push(a)};var d=$jscomp.global.setTimeout;b.prototype.asyncExecuteFunction=function(a){d(a,0)};b.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var a=
+this.batch_;this.batch_=[];for(var b=0;b<a.length;++b){var c=a[b];a[b]=null;try{c()}catch(k){this.asyncThrow_(k)}}}this.batch_=null};b.prototype.asyncThrow_=function(a){this.asyncExecuteFunction(function(){throw a;})};var e=function(a){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var b=this.createResolveAndReject_();try{a(b.resolve,b.reject)}catch(h){b.reject(h)}};e.prototype.createResolveAndReject_=function(){function a(a){return function(f){c||(c=!0,a.call(b,f))}}var b=this,c=!1;
+return{resolve:a(this.resolveTo_),reject:a(this.reject_)}};e.prototype.resolveTo_=function(a){if(a===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(a instanceof e)this.settleSameAsPromise_(a);else{a:switch(typeof a){case "object":var b=null!=a;break a;case "function":b=!0;break a;default:b=!1}b?this.resolveToNonPromiseObj_(a):this.fulfill_(a)}};e.prototype.resolveToNonPromiseObj_=function(a){var b=void 0;try{b=a.then}catch(h){this.reject_(h);return}"function"==typeof b?
+this.settleSameAsThenable_(b,a):this.fulfill_(a)};e.prototype.reject_=function(a){this.settle_(2,a)};e.prototype.fulfill_=function(a){this.settle_(1,a)};e.prototype.settle_=function(a,b){if(0!=this.state_)throw Error("Cannot settle("+a+", "+b+"): Promise already settled in state"+this.state_);this.state_=a;this.result_=b;this.executeOnSettledCallbacks_()};e.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var a=0;a<this.onSettledCallbacks_.length;++a)g.asyncExecute(this.onSettledCallbacks_[a]);
+this.onSettledCallbacks_=null}};var g=new b;e.prototype.settleSameAsPromise_=function(a){var b=this.createResolveAndReject_();a.callWhenSettled_(b.resolve,b.reject)};e.prototype.settleSameAsThenable_=function(a,b){var c=this.createResolveAndReject_();try{a.call(b,c.resolve,c.reject)}catch(k){c.reject(k)}};e.prototype.then=function(a,b){function c(a,b){return"function"==typeof a?function(b){try{d(a(b))}catch(m){f(m)}}:b}var d,f,l=new e(function(a,b){d=a;f=b});this.callWhenSettled_(c(a,d),c(b,f));return l};
+e.prototype.catch=function(a){return this.then(void 0,a)};e.prototype.callWhenSettled_=function(a,b){function c(){switch(d.state_){case 1:a(d.result_);break;case 2:b(d.result_);break;default:throw Error("Unexpected state: "+d.state_);}}var d=this;null==this.onSettledCallbacks_?g.asyncExecute(c):this.onSettledCallbacks_.push(c)};e.resolve=c;e.reject=function(a){return new e(function(b,c){c(a)})};e.race=function(a){return new e(function(b,d){for(var e=$jscomp.makeIterator(a),f=e.next();!f.done;f=e.next())c(f.value).callWhenSettled_(b,
+d)})};e.all=function(a){var b=$jscomp.makeIterator(a),d=b.next();return d.done?c([]):new e(function(a,e){function f(b){return function(c){g[b]=c;h--;0==h&&a(g)}}var g=[],h=0;do g.push(void 0),h++,c(d.value).callWhenSettled_(f(g.length-1),e),d=b.next();while(!d.done)})};return e},"es6","es3");$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};
+$jscomp.SymbolClass=function(a,b){this.$jscomp$symbol$id_=a;$jscomp.defineProperty(this,"description",{configurable:!0,writable:!0,value:b})};$jscomp.SymbolClass.prototype.toString=function(){return this.$jscomp$symbol$id_};$jscomp.Symbol=function(){function a(c){if(this instanceof a)throw new TypeError("Symbol is not a constructor");return new $jscomp.SymbolClass($jscomp.SYMBOL_PREFIX+(c||"")+"_"+b++,c)}var b=0;return a}();
+$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var a=$jscomp.global.Symbol.iterator;a||(a=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("Symbol.iterator"));"function"!=typeof Array.prototype[a]&&$jscomp.defineProperty(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return $jscomp.iteratorPrototype($jscomp.arrayIteratorImpl(this))}});$jscomp.initSymbolIterator=function(){}};
+$jscomp.initSymbolAsyncIterator=function(){$jscomp.initSymbol();var a=$jscomp.global.Symbol.asyncIterator;a||(a=$jscomp.global.Symbol.asyncIterator=$jscomp.global.Symbol("Symbol.asyncIterator"));$jscomp.initSymbolAsyncIterator=function(){}};$jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[$jscomp.global.Symbol.iterator]=function(){return this};return a};$jscomp.underscoreProtoCanBeSet=function(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(c){}return!1};
+$jscomp.setPrototypeOf="function"==typeof Object.setPrototypeOf?Object.setPrototypeOf:$jscomp.underscoreProtoCanBeSet()?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null;$jscomp.generator={};$jscomp.generator.ensureIteratorResultIsObject_=function(a){if(!(a instanceof Object))throw new TypeError("Iterator result "+a+" is not an object");};
+$jscomp.generator.Context=function(){this.isRunning_=!1;this.yieldAllIterator_=null;this.yieldResult=void 0;this.nextAddress=1;this.finallyAddress_=this.catchAddress_=0;this.finallyContexts_=this.abruptCompletion_=null};$jscomp.generator.Context.prototype.start_=function(){if(this.isRunning_)throw new TypeError("Generator is already running");this.isRunning_=!0};$jscomp.generator.Context.prototype.stop_=function(){this.isRunning_=!1};
+$jscomp.generator.Context.prototype.jumpToErrorHandler_=function(){this.nextAddress=this.catchAddress_||this.finallyAddress_};$jscomp.generator.Context.prototype.next_=function(a){this.yieldResult=a};$jscomp.generator.Context.prototype.throw_=function(a){this.abruptCompletion_={exception:a,isException:!0};this.jumpToErrorHandler_()};$jscomp.generator.Context.prototype.return=function(a){this.abruptCompletion_={return:a};this.nextAddress=this.finallyAddress_};
+$jscomp.generator.Context.prototype.jumpThroughFinallyBlocks=function(a){this.abruptCompletion_={jumpTo:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.yield=function(a,b){this.nextAddress=b;return{value:a}};$jscomp.generator.Context.prototype.yieldAll=function(a,b){a=$jscomp.makeIterator(a);var c=a.next();$jscomp.generator.ensureIteratorResultIsObject_(c);if(c.done)this.yieldResult=c.value,this.nextAddress=b;else return this.yieldAllIterator_=a,this.yield(c.value,b)};
+$jscomp.generator.Context.prototype.jumpTo=function(a){this.nextAddress=a};$jscomp.generator.Context.prototype.jumpToEnd=function(){this.nextAddress=0};$jscomp.generator.Context.prototype.setCatchFinallyBlocks=function(a,b){this.catchAddress_=a;void 0!=b&&(this.finallyAddress_=b)};$jscomp.generator.Context.prototype.setFinallyBlock=function(a){this.catchAddress_=0;this.finallyAddress_=a||0};$jscomp.generator.Context.prototype.leaveTryBlock=function(a,b){this.nextAddress=a;this.catchAddress_=b||0};
+$jscomp.generator.Context.prototype.enterCatchBlock=function(a){this.catchAddress_=a||0;a=this.abruptCompletion_.exception;this.abruptCompletion_=null;return a};$jscomp.generator.Context.prototype.enterFinallyBlock=function(a,b,c){c?this.finallyContexts_[c]=this.abruptCompletion_:this.finallyContexts_=[this.abruptCompletion_];this.catchAddress_=a||0;this.finallyAddress_=b||0};
+$jscomp.generator.Context.prototype.leaveFinallyBlock=function(a,b){b=this.finallyContexts_.splice(b||0)[0];if(b=this.abruptCompletion_=this.abruptCompletion_||b){if(b.isException)return this.jumpToErrorHandler_();void 0!=b.jumpTo&&this.finallyAddress_<b.jumpTo?(this.nextAddress=b.jumpTo,this.abruptCompletion_=null):this.nextAddress=this.finallyAddress_}else this.nextAddress=a};$jscomp.generator.Context.prototype.forIn=function(a){return new $jscomp.generator.Context.PropertyIterator(a)};
+$jscomp.generator.Context.PropertyIterator=function(a){this.object_=a;this.properties_=[];for(var b in a)this.properties_.push(b);this.properties_.reverse()};$jscomp.generator.Context.PropertyIterator.prototype.getNext=function(){for(;0<this.properties_.length;){var a=this.properties_.pop();if(a in this.object_)return a}return null};$jscomp.generator.Engine_=function(a){this.context_=new $jscomp.generator.Context;this.program_=a};
+$jscomp.generator.Engine_.prototype.next_=function(a){this.context_.start_();if(this.context_.yieldAllIterator_)return this.yieldAllStep_(this.context_.yieldAllIterator_.next,a,this.context_.next_);this.context_.next_(a);return this.nextStep_()};
+$jscomp.generator.Engine_.prototype.return_=function(a){this.context_.start_();var b=this.context_.yieldAllIterator_;if(b)return this.yieldAllStep_("return"in b?b["return"]:function(a){return{value:a,done:!0}},a,this.context_.return);this.context_.return(a);return this.nextStep_()};
+$jscomp.generator.Engine_.prototype.throw_=function(a){this.context_.start_();if(this.context_.yieldAllIterator_)return this.yieldAllStep_(this.context_.yieldAllIterator_["throw"],a,this.context_.next_);this.context_.throw_(a);return this.nextStep_()};
+$jscomp.generator.Engine_.prototype.yieldAllStep_=function(a,b,c){try{var d=a.call(this.context_.yieldAllIterator_,b);$jscomp.generator.ensureIteratorResultIsObject_(d);if(!d.done)return this.context_.stop_(),d;var e=d.value}catch(g){return this.context_.yieldAllIterator_=null,this.context_.throw_(g),this.nextStep_()}this.context_.yieldAllIterator_=null;c.call(this.context_,e);return this.nextStep_()};
+$jscomp.generator.Engine_.prototype.nextStep_=function(){for(;this.context_.nextAddress;)try{var a=this.program_(this.context_);if(a)return this.context_.stop_(),{value:a.value,done:!1}}catch(b){this.context_.yieldResult=void 0,this.context_.throw_(b)}this.context_.stop_();if(this.context_.abruptCompletion_){a=this.context_.abruptCompletion_;this.context_.abruptCompletion_=null;if(a.isException)throw a.exception;return{value:a.return,done:!0}}return{value:void 0,done:!0}};
+$jscomp.generator.Generator_=function(a){this.next=function(b){return a.next_(b)};this.throw=function(b){return a.throw_(b)};this.return=function(b){return a.return_(b)};$jscomp.initSymbolIterator();this[Symbol.iterator]=function(){return this}};$jscomp.generator.createGenerator=function(a,b){b=new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(b));$jscomp.setPrototypeOf&&$jscomp.setPrototypeOf(b,a.prototype);return b};
+$jscomp.asyncExecutePromiseGenerator=function(a){function b(b){return a.next(b)}function c(b){return a.throw(b)}return new Promise(function(d,e){function g(a){a.done?d(a.value):Promise.resolve(a.value).then(b,c).then(g,e)}g(a.next())})};$jscomp.asyncExecutePromiseGeneratorFunction=function(a){return $jscomp.asyncExecutePromiseGenerator(a())};$jscomp.asyncExecutePromiseGeneratorProgram=function(a){return $jscomp.asyncExecutePromiseGenerator(new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(a)))};
+$jscomp.polyfill("globalThis",function(a){return a||$jscomp.global},"es_next","es3");var fetchButton=document.querySelector(".js-fetchButton");fetchButton&&fetchButton.addEventListener("click",function(a){a.preventDefault();fetchPath()});
+function fetchPath(){var a,b,c;return $jscomp.asyncExecutePromiseGeneratorProgram(function(d){if(1==d.nextAddress)return a=document.querySelector(".js-fetchMessage"),a.textContent="Fetching "+a.dataset.path,document.querySelector(".js-fetchMessageSecondary").textContent="Feel free to navigate away and check back later, we'll keep working on it!",document.querySelector(".js-fetchButton").style.display="none",document.querySelector(".js-fetchLoading").style.display="block",d.yield(fetch("/fetch"+window.location.pathname),
+2);if(3!=d.nextAddress)return b=d.yieldResult,b.ok?(window.location.reload(),d.return()):d.yield(b.text(),3);c=d.yieldResult;document.querySelector(".js-fetchLoading").style.display="none";document.querySelector(".js-fetchMessageSecondary").textContent="";document.querySelector(".js-fetchMessage").textContent=c;d.jumpToEnd()})};
diff --git a/devtools/compile_js.sh b/devtools/compile_js.sh
index 69191f9..e53cb4b 100755
--- a/devtools/compile_js.sh
+++ b/devtools/compile_js.sh
@@ -42,6 +42,7 @@
$cmd $JSDIR/base.min.js $JSDIR/{site,analytics}.js
# TODO: once this is not an experiment, add it to the line above.
$cmd $JSDIR/completion.min.js $JSDIR/completion.js
+ $cmd $JSDIR/fetch.min.js $JSDIR/fetch.js
$cmd $JSDIR/jump.min.js third_party/dialog-polyfill/dialog-polyfill.js $JSDIR/jump.js
}
diff --git a/internal/frontend/details.go b/internal/frontend/details.go
index f82658b..b7f058e 100644
--- a/internal/frontend/details.go
+++ b/internal/frontend/details.go
@@ -277,7 +277,7 @@
return &serverError{
status: http.StatusNotFound,
epage: &errorPage{
- templateName: "notfound.tmpl",
+ templateName: "fetch.tmpl",
messageTemplate: `
<h3 class="NotFound-message">Oops! {{.}} does not exist.</h3>
<p class="NotFound-message js-notFoundMessage">
diff --git a/internal/frontend/server.go b/internal/frontend/server.go
index a72ef01..1bbc34e 100644
--- a/internal/frontend/server.go
+++ b/internal/frontend/server.go
@@ -400,7 +400,7 @@
htmlSets := [][]string{
{"index.tmpl"},
{"error.tmpl"},
- {"notfound.tmpl"},
+ {"fetch.tmpl"},
{"search.tmpl"},
{"search_help.tmpl"},
{"license_policy.tmpl"},
diff --git a/internal/middleware/secureheaders.go b/internal/middleware/secureheaders.go
index 7eee866..59c04fa 100644
--- a/internal/middleware/secureheaders.go
+++ b/internal/middleware/secureheaders.go
@@ -15,14 +15,14 @@
"'sha256-d6W7MwuGWbguTHRzQhf5QN1jXmNo9Ao218saZkWLWZI='",
"'sha256-CCu0fuIQFBHSCEpfR6ZRzzcczJIS/VGMGrez8LR49WY='",
"'sha256-qPGTOKPn+niRiNKQIEX0Ktwuj+D+iPQWIxnlhPicw58='",
- // From content/static/html/pages/notfound.tmpl
- "'sha256-h5L4TV5GzTaBQYCnA8tDw9+9/AIdK9dwgkwlqFjVqEI='",
// From content/static/html/pages/details.tmpl
"'sha256-s16e7aT7Gsajq5UH1DbaEFEnNx2VjvS5Xixcxwm4+F8='",
// From content/static/html/pages/pkg_doc.tmpl
"'sha256-AvMTqQ+22BA0Nsht+ajju4EQseFQsoG1RxW3Nh6M+wc='",
// From content/static/html/worker/index.tmpl
"'sha256-5EpitFYSzGNQNUsqi5gAaLqnI3ZWfcRo/6gLTO0oCoE='",
+ // From content/static/html/pages/fetch.tmpl
+ "'sha256-1J6DWwTWs/QDZ2+ORDuUQCibmFnXXaNXYOtc0Jk6VU4='",
}
// SecureHeaders adds a content-security-policy and other security-related