content/static: update empty message in jump to modal

Change-Id: I0efd36a203f094db922ae3ceeaa0d3fa658a6109
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/310230
Trust: Jamal Carvalho <jamal@golang.org>
Run-TryBot: Jamal Carvalho <jamal@golang.org>
Reviewed-by: Julie Qiu <julie@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
diff --git a/content/static/js/jump.js b/content/static/js/jump.js
index 86873e8..33382c4 100644
--- a/content/static/js/jump.js
+++ b/content/static/js/jump.js
@@ -3,5 +3,5 @@
  * 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.
- */const jumpDialog=document.querySelector(".JumpDialog"),jumpBody=jumpDialog?.querySelector(".JumpDialog-body"),jumpList=jumpDialog?.querySelector(".JumpDialog-list"),jumpFilter=jumpDialog?.querySelector(".JumpDialog-input"),searchInput=document.querySelector(".js-searchFocus"),doc=document.querySelector(".js-documentation");function loadPolyfill(){return import(`${window.location.origin}/third_party/dialog-polyfill/dialog-polyfill.esm.js`)}jumpDialog&&!jumpDialog.showModal&&loadPolyfill().then(({default:t})=>{t.registerDialog(jumpDialog)});let jumpListItems;function collectJumpListItems(){const t=[];if(!!doc){for(const e of doc.querySelectorAll("[data-kind]"))t.push(newJumpListItem(e));for(const e of t)e.link.addEventListener("click",function(){jumpDialog?.close()});return t.sort(function(e,n){return e.lower.localeCompare(n.lower)}),t}}function newJumpListItem(t){const e=document.createElement("a"),n=t.getAttribute("id");e.setAttribute("href","#"+n),e.setAttribute("tabindex","-1");const o=t.getAttribute("data-kind");return{link:e,name:n??"",kind:o??"",lower:n?.toLowerCase()??""}}let lastFilterValue,activeJumpItem=-1;function updateJumpList(t){for(lastFilterValue=t,jumpListItems||(jumpListItems=collectJumpListItems()),setActiveJumpItem(-1);jumpList?.firstChild;)jumpList.firstChild.remove();if(t){const e=t.toLowerCase(),n=[],o=[],c=[],l=(i,s,r)=>i.name.substring(0,s)+"<b>"+i.name.substring(s,r)+"</b>"+i.name.substring(r);for(const i of jumpListItems??[]){const s=i.name.toLowerCase();if(s===e)i.link.innerHTML=l(i,0,i.name.length),n.push(i);else if(s.startsWith(e))i.link.innerHTML=l(i,0,t.length),o.push(i);else{const r=s.indexOf(e);r>-1&&(i.link.innerHTML=l(i,r,r+t.length),c.push(i))}}for(const i of n.concat(o).concat(c))jumpList?.appendChild(i.link)}else{if(!jumpListItems||jumpListItems.length===0){const e=document.createElement("i");e.innerHTML="No jump items found.",jumpList?.appendChild(e)}for(const e of jumpListItems??[])e.link.innerHTML=e.name+" <i>"+e.kind+"</i>",jumpList?.appendChild(e.link)}jumpBody&&(jumpBody.scrollTop=0),jumpListItems?.length&&jumpList&&jumpList.children.length>0&&setActiveJumpItem(0)}function setActiveJumpItem(t){const e=jumpList?.children;if(!(!e||!jumpBody)){if(activeJumpItem>=0&&e[activeJumpItem].classList.remove("JumpDialog-active"),t>=e.length&&(t=e.length-1),t>=0){e[t].classList.add("JumpDialog-active");const n=e[t].offsetTop-e[0].offsetTop,o=n+e[t].clientHeight;n<jumpBody.scrollTop?jumpBody.scrollTop=n:o>jumpBody.scrollTop+jumpBody.clientHeight&&(jumpBody.scrollTop=o-jumpBody.clientHeight)}activeJumpItem=t}}function incActiveJumpItem(t){if(activeJumpItem<0)return;let e=activeJumpItem+t;e<0&&(e=0),setActiveJumpItem(e)}jumpFilter?.addEventListener("keyup",function(){jumpFilter.value.toUpperCase()!=lastFilterValue.toUpperCase()&&updateJumpList(jumpFilter.value)}),jumpFilter?.addEventListener("keydown",function(t){const e=38,n=40,o=13;switch(t.which){case e:incActiveJumpItem(-1),t.preventDefault();break;case n:incActiveJumpItem(1),t.preventDefault();break;case o:activeJumpItem>=0&&jumpList&&jumpList.children[activeJumpItem].click();break}});const shortcutsDialog=document.querySelector(".ShortcutsDialog");shortcutsDialog&&!shortcutsDialog.showModal&&loadPolyfill().then(({default:t})=>{t.registerDialog(shortcutsDialog)}),document.addEventListener("keypress",function(t){if(jumpDialog?.open||shortcutsDialog?.open)return;const e=t.target,n=e?.tagName;if(n=="INPUT"||n=="SELECT"||n=="TEXTAREA"||e?.contentEditable=="true"||t.metaKey||t.ctrlKey)return;switch(String.fromCharCode(t.which)){case"f":case"F":t.preventDefault(),jumpFilter&&(jumpFilter.value=""),jumpDialog?.showModal(),updateJumpList("");break;case"?":shortcutsDialog?.showModal();break;case"/":searchInput&&!window.navigator.userAgent.includes("Firefox")&&(t.preventDefault(),searchInput.focus());break}});const jumpOutlineInput=document.querySelector(".js-jumpToInput");jumpOutlineInput&&jumpOutlineInput.addEventListener("click",()=>{jumpFilter&&(jumpFilter.value=""),jumpDialog?.showModal(),updateJumpList("")});
+ */const jumpDialog=document.querySelector(".JumpDialog"),jumpBody=jumpDialog?.querySelector(".JumpDialog-body"),jumpList=jumpDialog?.querySelector(".JumpDialog-list"),jumpFilter=jumpDialog?.querySelector(".JumpDialog-input"),searchInput=document.querySelector(".js-searchFocus"),doc=document.querySelector(".js-documentation");function loadPolyfill(){return import(`${window.location.origin}/third_party/dialog-polyfill/dialog-polyfill.esm.js`)}jumpDialog&&!jumpDialog.showModal&&loadPolyfill().then(({default:t})=>{t.registerDialog(jumpDialog)});let jumpListItems;function collectJumpListItems(){const t=[];if(!!doc){for(const e of doc.querySelectorAll("[data-kind]"))t.push(newJumpListItem(e));for(const e of t)e.link.addEventListener("click",function(){jumpDialog?.close()});return t.sort(function(e,n){return e.lower.localeCompare(n.lower)}),t}}function newJumpListItem(t){const e=document.createElement("a"),n=t.getAttribute("id");e.setAttribute("href","#"+n),e.setAttribute("tabindex","-1");const o=t.getAttribute("data-kind");return{link:e,name:n??"",kind:o??"",lower:n?.toLowerCase()??""}}let lastFilterValue,activeJumpItem=-1;function updateJumpList(t){for(lastFilterValue=t,jumpListItems||(jumpListItems=collectJumpListItems()),setActiveJumpItem(-1);jumpList?.firstChild;)jumpList.firstChild.remove();if(t){const e=t.toLowerCase(),n=[],o=[],c=[],l=(i,r,s)=>i.name.substring(0,r)+"<b>"+i.name.substring(r,s)+"</b>"+i.name.substring(s);for(const i of jumpListItems??[]){const r=i.name.toLowerCase();if(r===e)i.link.innerHTML=l(i,0,i.name.length),n.push(i);else if(r.startsWith(e))i.link.innerHTML=l(i,0,t.length),o.push(i);else{const s=r.indexOf(e);s>-1&&(i.link.innerHTML=l(i,s,s+t.length),c.push(i))}}for(const i of n.concat(o).concat(c))jumpList?.appendChild(i.link)}else{if(!jumpListItems||jumpListItems.length===0){const e=document.createElement("i");e.innerHTML="There are no identifiers on this page.",jumpList?.appendChild(e)}for(const e of jumpListItems??[])e.link.innerHTML=e.name+" <i>"+e.kind+"</i>",jumpList?.appendChild(e.link)}jumpBody&&(jumpBody.scrollTop=0),jumpListItems?.length&&jumpList&&jumpList.children.length>0&&setActiveJumpItem(0)}function setActiveJumpItem(t){const e=jumpList?.children;if(!(!e||!jumpBody)){if(activeJumpItem>=0&&e[activeJumpItem].classList.remove("JumpDialog-active"),t>=e.length&&(t=e.length-1),t>=0){e[t].classList.add("JumpDialog-active");const n=e[t].offsetTop-e[0].offsetTop,o=n+e[t].clientHeight;n<jumpBody.scrollTop?jumpBody.scrollTop=n:o>jumpBody.scrollTop+jumpBody.clientHeight&&(jumpBody.scrollTop=o-jumpBody.clientHeight)}activeJumpItem=t}}function incActiveJumpItem(t){if(activeJumpItem<0)return;let e=activeJumpItem+t;e<0&&(e=0),setActiveJumpItem(e)}jumpFilter?.addEventListener("keyup",function(){jumpFilter.value.toUpperCase()!=lastFilterValue.toUpperCase()&&updateJumpList(jumpFilter.value)}),jumpFilter?.addEventListener("keydown",function(t){const e=38,n=40,o=13;switch(t.which){case e:incActiveJumpItem(-1),t.preventDefault();break;case n:incActiveJumpItem(1),t.preventDefault();break;case o:activeJumpItem>=0&&jumpList&&jumpList.children[activeJumpItem].click();break}});const shortcutsDialog=document.querySelector(".ShortcutsDialog");shortcutsDialog&&!shortcutsDialog.showModal&&loadPolyfill().then(({default:t})=>{t.registerDialog(shortcutsDialog)}),document.addEventListener("keypress",function(t){if(jumpDialog?.open||shortcutsDialog?.open)return;const e=t.target,n=e?.tagName;if(n=="INPUT"||n=="SELECT"||n=="TEXTAREA"||e?.contentEditable=="true"||t.metaKey||t.ctrlKey)return;switch(String.fromCharCode(t.which)){case"f":case"F":t.preventDefault(),jumpFilter&&(jumpFilter.value=""),jumpDialog?.showModal(),updateJumpList("");break;case"?":shortcutsDialog?.showModal();break;case"/":searchInput&&!window.navigator.userAgent.includes("Firefox")&&(t.preventDefault(),searchInput.focus());break}});const jumpOutlineInput=document.querySelector(".js-jumpToInput");jumpOutlineInput&&jumpOutlineInput.addEventListener("click",()=>{jumpFilter&&(jumpFilter.value=""),jumpDialog?.showModal(),updateJumpList("")});
 //# sourceMappingURL=jump.js.map
diff --git a/content/static/js/jump.js.map b/content/static/js/jump.js.map
index eb738db..0d5bb06 100644
--- a/content/static/js/jump.js.map
+++ b/content/static/js/jump.js.map
@@ -1,7 +1,7 @@
 {
   "version": 3,
   "sources": ["jump.ts"],
-  "sourcesContent": ["/*!\n * @license\n * Copyright 2019-2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the behavior of the \"jump to identifer\" dialog for Go\n// package documentation, as well as the simple dialog that displays keyboard\n// shortcuts.\n\n// The DOM for the dialogs is at the bottom of content/static/html/pages/pkg_doc.tmpl.\n// The CSS is in content/static/css/stylesheet.css.\n\n// The dialog is activated by pressing the 'f' key. It presents a list\n// (#JumpDialog-list) of all Go identifiers displayed in the documentation.\n// Entering text in the dialog's text box (#JumpDialog-filter) restricts the\n// list to identifiers containing the text. Clicking on an identifier jumps to\n// its documentation.\n\n// This code is based on\n// https://go.googlesource.com/gddo/+/refs/heads/master/gddo-server/assets/site.js.\n// It was modified to remove the dependence on jquery and bootstrap.\n\nconst jumpDialog = document.querySelector<HTMLDialogElement>('.JumpDialog');\nconst jumpBody = jumpDialog?.querySelector<HTMLDivElement>('.JumpDialog-body');\nconst jumpList = jumpDialog?.querySelector<HTMLDivElement>('.JumpDialog-list');\nconst jumpFilter = jumpDialog?.querySelector<HTMLInputElement>('.JumpDialog-input');\nconst searchInput = document.querySelector<HTMLInputElement>('.js-searchFocus');\nconst doc = document.querySelector<HTMLDivElement>('.js-documentation');\n\nfunction loadPolyfill() {\n  return import(`${window.location.origin}/third_party/dialog-polyfill/dialog-polyfill.esm.js`);\n}\n\nif (jumpDialog && !jumpDialog.showModal) {\n  loadPolyfill().then(({ default: dialogPolyfill }) => {\n    dialogPolyfill.registerDialog(jumpDialog);\n  });\n}\n\ninterface JumpListItem {\n  link: HTMLAnchorElement;\n  name: string;\n  kind: string;\n  lower: string;\n}\n\nlet jumpListItems: JumpListItem[] | undefined; // All the identifiers in the doc; computed only once.\n\n// collectJumpListItems returns a list of items, one for each identifier in the\n// documentation on the current page.\n//\n// It uses the data-kind attribute generated in the documentation HTML to find\n// the identifiers and their id attributes.\n//\n// If there are no data-kind attributes, then we have older doc; fall back to\n// a less precise method.\nfunction collectJumpListItems() {\n  const items = [];\n  if (!doc) return;\n  for (const el of doc.querySelectorAll('[data-kind]')) {\n    items.push(newJumpListItem(el));\n  }\n\n  // Clicking on any of the links closes the dialog.\n  for (const item of items) {\n    item.link.addEventListener('click', function () {\n      jumpDialog?.close();\n    });\n  }\n  // Sort case-insensitively by identifier name.\n  items.sort(function (a, b) {\n    return a.lower.localeCompare(b.lower);\n  });\n  return items;\n}\n\n// newJumpListItem creates a new item for the DOM element el.\n// An item is an object with:\n// - name: the element's id (which is the identifer name)\n// - kind: the element's kind (function, variable, etc.),\n// - link: a link ('a' tag) to the element\n// - lower: the name in lower case, just for sorting\nfunction newJumpListItem(el: Element): JumpListItem {\n  const a = document.createElement('a');\n  const name = el.getAttribute('id');\n  a.setAttribute('href', '#' + name);\n  a.setAttribute('tabindex', '-1');\n  const kind = el.getAttribute('data-kind');\n  return {\n    link: a,\n    name: name ?? '',\n    kind: kind ?? '',\n    lower: name?.toLowerCase() ?? '', // for sorting\n  };\n}\n\nlet lastFilterValue: string; // The last contents of the filter text box.\nlet activeJumpItem = -1; // The index of the currently active item in the list.\n\n// updateJumpList sets the elements of the dialog list to\n// everything whose name contains filter.\nfunction updateJumpList(filter: string) {\n  lastFilterValue = filter;\n  if (!jumpListItems) {\n    jumpListItems = collectJumpListItems();\n  }\n  setActiveJumpItem(-1);\n\n  // Remove all children from list.\n  while (jumpList?.firstChild) {\n    jumpList.firstChild.remove();\n  }\n\n  if (filter) {\n    // A filter is set. We treat the filter as a substring that can appear in\n    // an item name (case insensitive), and find the following matches - in\n    // order of priority:\n    //\n    // 1. Exact matches (the filter matches the item's name exactly)\n    // 2. Prefix matches (the item's name starts with filter)\n    // 3. Infix matches (the filter is a substring of the item's name)\n    const filterLowerCase = filter.toLowerCase();\n\n    const exactMatches = [];\n    const prefixMatches = [];\n    const infixMatches = [];\n\n    // makeLinkHtml creates the link name HTML for a list item. item is the DOM\n    // item. item.name.substr(boldStart, boldEnd) will be bolded.\n    const makeLinkHtml = (item: JumpListItem, boldStart: number, boldEnd: number) => {\n      return (\n        item.name.substring(0, boldStart) +\n        '<b>' +\n        item.name.substring(boldStart, boldEnd) +\n        '</b>' +\n        item.name.substring(boldEnd)\n      );\n    };\n\n    for (const item of jumpListItems ?? []) {\n      const nameLowerCase = item.name.toLowerCase();\n\n      if (nameLowerCase === filterLowerCase) {\n        item.link.innerHTML = makeLinkHtml(item, 0, item.name.length);\n        exactMatches.push(item);\n      } else if (nameLowerCase.startsWith(filterLowerCase)) {\n        item.link.innerHTML = makeLinkHtml(item, 0, filter.length);\n        prefixMatches.push(item);\n      } else {\n        const index = nameLowerCase.indexOf(filterLowerCase);\n        if (index > -1) {\n          item.link.innerHTML = makeLinkHtml(item, index, index + filter.length);\n          infixMatches.push(item);\n        }\n      }\n    }\n\n    for (const item of exactMatches.concat(prefixMatches).concat(infixMatches)) {\n      jumpList?.appendChild(item.link);\n    }\n  } else {\n    if (!jumpListItems || jumpListItems.length === 0) {\n      const msg = document.createElement('i');\n      msg.innerHTML = 'No jump items found.';\n      jumpList?.appendChild(msg);\n    }\n    // No filter set; display all items in their existing order.\n    for (const item of jumpListItems ?? []) {\n      item.link.innerHTML = item.name + ' <i>' + item.kind + '</i>';\n      jumpList?.appendChild(item.link);\n    }\n  }\n\n  if (jumpBody) {\n    jumpBody.scrollTop = 0;\n  }\n  if (jumpListItems?.length && jumpList && jumpList.children.length > 0) {\n    setActiveJumpItem(0);\n  }\n}\n\n// Set the active jump item to n.\nfunction setActiveJumpItem(n: number) {\n  const cs = jumpList?.children as HTMLCollectionOf<HTMLElement> | null | undefined;\n  if (!cs || !jumpBody) {\n    return;\n  }\n  if (activeJumpItem >= 0) {\n    cs[activeJumpItem].classList.remove('JumpDialog-active');\n  }\n  if (n >= cs.length) {\n    n = cs.length - 1;\n  }\n  if (n >= 0) {\n    cs[n].classList.add('JumpDialog-active');\n\n    // Scroll so the active item is visible.\n    // For some reason cs[n].scrollIntoView() doesn't behave as I'd expect:\n    // it moves the entire dialog box in the viewport.\n\n    // Get the top and bottom of the active item relative to jumpBody.\n    const activeTop = cs[n].offsetTop - cs[0].offsetTop;\n    const activeBottom = activeTop + cs[n].clientHeight;\n    if (activeTop < jumpBody.scrollTop) {\n      // Off the top; scroll up.\n      jumpBody.scrollTop = activeTop;\n    } else if (activeBottom > jumpBody.scrollTop + jumpBody.clientHeight) {\n      // Off the bottom; scroll down.\n      jumpBody.scrollTop = activeBottom - jumpBody.clientHeight;\n    }\n  }\n  activeJumpItem = n;\n}\n\n// Increment the activeJumpItem by delta.\nfunction incActiveJumpItem(delta: number) {\n  if (activeJumpItem < 0) {\n    return;\n  }\n  let n = activeJumpItem + delta;\n  if (n < 0) {\n    n = 0;\n  }\n  setActiveJumpItem(n);\n}\n\n// Pressing a key in the filter updates the list (if the filter actually changed).\njumpFilter?.addEventListener('keyup', function () {\n  if (jumpFilter.value.toUpperCase() != lastFilterValue.toUpperCase()) {\n    updateJumpList(jumpFilter.value);\n  }\n});\n\n// Pressing enter in the filter selects the first element in the list.\njumpFilter?.addEventListener('keydown', function (event) {\n  const upArrow = 38;\n  const downArrow = 40;\n  const enterKey = 13;\n  switch (event.which) {\n    case upArrow:\n      incActiveJumpItem(-1);\n      event.preventDefault();\n      break;\n    case downArrow:\n      incActiveJumpItem(1);\n      event.preventDefault();\n      break;\n    case enterKey:\n      if (activeJumpItem >= 0) {\n        if (jumpList) {\n          (jumpList.children[activeJumpItem] as HTMLElement).click();\n        }\n      }\n      break;\n  }\n});\n\nconst shortcutsDialog = document.querySelector<HTMLDialogElement>('.ShortcutsDialog');\nif (shortcutsDialog && !shortcutsDialog.showModal) {\n  loadPolyfill().then(({ default: dialogPolyfill }) => {\n    dialogPolyfill.registerDialog(shortcutsDialog);\n  });\n}\n\n// Keyboard shortcuts:\n// - Pressing '/' focuses the search box\n// - Pressing 'f' or 'F' opens the jump-to-identifier dialog.\n// - Pressing '?' opens up the shortcut dialog.\n// Ignore a keypress if a dialog is already open, or if it is pressed on a\n// component that wants to consume it.\ndocument.addEventListener('keypress', function (e) {\n  if (jumpDialog?.open || shortcutsDialog?.open) {\n    return;\n  }\n  const target = e.target as HTMLElement | null;\n  const t = target?.tagName;\n  if (t == 'INPUT' || t == 'SELECT' || t == 'TEXTAREA') {\n    return;\n  }\n  if (target?.contentEditable == 'true') {\n    return;\n  }\n  if (e.metaKey || e.ctrlKey) {\n    return;\n  }\n  const ch = String.fromCharCode(e.which);\n  switch (ch) {\n    case 'f':\n    case 'F':\n      e.preventDefault();\n      if (jumpFilter) {\n        jumpFilter.value = '';\n      }\n      jumpDialog?.showModal();\n      updateJumpList('');\n      break;\n    case '?':\n      shortcutsDialog?.showModal();\n      break;\n    case '/':\n      // Favoring the Firefox quick find feature over search input\n      // focus. See: https://github.com/golang/go/issues/41093.\n      if (searchInput && !window.navigator.userAgent.includes('Firefox')) {\n        e.preventDefault();\n        searchInput.focus();\n      }\n      break;\n  }\n});\n\nconst jumpOutlineInput = document.querySelector('.js-jumpToInput');\nif (jumpOutlineInput) {\n  jumpOutlineInput.addEventListener('click', () => {\n    if (jumpFilter) {\n      jumpFilter.value = '';\n    }\n    jumpDialog?.showModal();\n    updateJumpList('');\n  });\n}\n"],
-  "mappings": "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",
+  "sourcesContent": ["/*!\n * @license\n * Copyright 2019-2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n// This file implements the behavior of the \"jump to identifer\" dialog for Go\n// package documentation, as well as the simple dialog that displays keyboard\n// shortcuts.\n\n// The DOM for the dialogs is at the bottom of content/static/html/pages/pkg_doc.tmpl.\n// The CSS is in content/static/css/stylesheet.css.\n\n// The dialog is activated by pressing the 'f' key. It presents a list\n// (#JumpDialog-list) of all Go identifiers displayed in the documentation.\n// Entering text in the dialog's text box (#JumpDialog-filter) restricts the\n// list to identifiers containing the text. Clicking on an identifier jumps to\n// its documentation.\n\n// This code is based on\n// https://go.googlesource.com/gddo/+/refs/heads/master/gddo-server/assets/site.js.\n// It was modified to remove the dependence on jquery and bootstrap.\n\nconst jumpDialog = document.querySelector<HTMLDialogElement>('.JumpDialog');\nconst jumpBody = jumpDialog?.querySelector<HTMLDivElement>('.JumpDialog-body');\nconst jumpList = jumpDialog?.querySelector<HTMLDivElement>('.JumpDialog-list');\nconst jumpFilter = jumpDialog?.querySelector<HTMLInputElement>('.JumpDialog-input');\nconst searchInput = document.querySelector<HTMLInputElement>('.js-searchFocus');\nconst doc = document.querySelector<HTMLDivElement>('.js-documentation');\n\nfunction loadPolyfill() {\n  return import(`${window.location.origin}/third_party/dialog-polyfill/dialog-polyfill.esm.js`);\n}\n\nif (jumpDialog && !jumpDialog.showModal) {\n  loadPolyfill().then(({ default: dialogPolyfill }) => {\n    dialogPolyfill.registerDialog(jumpDialog);\n  });\n}\n\ninterface JumpListItem {\n  link: HTMLAnchorElement;\n  name: string;\n  kind: string;\n  lower: string;\n}\n\nlet jumpListItems: JumpListItem[] | undefined; // All the identifiers in the doc; computed only once.\n\n// collectJumpListItems returns a list of items, one for each identifier in the\n// documentation on the current page.\n//\n// It uses the data-kind attribute generated in the documentation HTML to find\n// the identifiers and their id attributes.\n//\n// If there are no data-kind attributes, then we have older doc; fall back to\n// a less precise method.\nfunction collectJumpListItems() {\n  const items = [];\n  if (!doc) return;\n  for (const el of doc.querySelectorAll('[data-kind]')) {\n    items.push(newJumpListItem(el));\n  }\n\n  // Clicking on any of the links closes the dialog.\n  for (const item of items) {\n    item.link.addEventListener('click', function () {\n      jumpDialog?.close();\n    });\n  }\n  // Sort case-insensitively by identifier name.\n  items.sort(function (a, b) {\n    return a.lower.localeCompare(b.lower);\n  });\n  return items;\n}\n\n// newJumpListItem creates a new item for the DOM element el.\n// An item is an object with:\n// - name: the element's id (which is the identifer name)\n// - kind: the element's kind (function, variable, etc.),\n// - link: a link ('a' tag) to the element\n// - lower: the name in lower case, just for sorting\nfunction newJumpListItem(el: Element): JumpListItem {\n  const a = document.createElement('a');\n  const name = el.getAttribute('id');\n  a.setAttribute('href', '#' + name);\n  a.setAttribute('tabindex', '-1');\n  const kind = el.getAttribute('data-kind');\n  return {\n    link: a,\n    name: name ?? '',\n    kind: kind ?? '',\n    lower: name?.toLowerCase() ?? '', // for sorting\n  };\n}\n\nlet lastFilterValue: string; // The last contents of the filter text box.\nlet activeJumpItem = -1; // The index of the currently active item in the list.\n\n// updateJumpList sets the elements of the dialog list to\n// everything whose name contains filter.\nfunction updateJumpList(filter: string) {\n  lastFilterValue = filter;\n  if (!jumpListItems) {\n    jumpListItems = collectJumpListItems();\n  }\n  setActiveJumpItem(-1);\n\n  // Remove all children from list.\n  while (jumpList?.firstChild) {\n    jumpList.firstChild.remove();\n  }\n\n  if (filter) {\n    // A filter is set. We treat the filter as a substring that can appear in\n    // an item name (case insensitive), and find the following matches - in\n    // order of priority:\n    //\n    // 1. Exact matches (the filter matches the item's name exactly)\n    // 2. Prefix matches (the item's name starts with filter)\n    // 3. Infix matches (the filter is a substring of the item's name)\n    const filterLowerCase = filter.toLowerCase();\n\n    const exactMatches = [];\n    const prefixMatches = [];\n    const infixMatches = [];\n\n    // makeLinkHtml creates the link name HTML for a list item. item is the DOM\n    // item. item.name.substr(boldStart, boldEnd) will be bolded.\n    const makeLinkHtml = (item: JumpListItem, boldStart: number, boldEnd: number) => {\n      return (\n        item.name.substring(0, boldStart) +\n        '<b>' +\n        item.name.substring(boldStart, boldEnd) +\n        '</b>' +\n        item.name.substring(boldEnd)\n      );\n    };\n\n    for (const item of jumpListItems ?? []) {\n      const nameLowerCase = item.name.toLowerCase();\n\n      if (nameLowerCase === filterLowerCase) {\n        item.link.innerHTML = makeLinkHtml(item, 0, item.name.length);\n        exactMatches.push(item);\n      } else if (nameLowerCase.startsWith(filterLowerCase)) {\n        item.link.innerHTML = makeLinkHtml(item, 0, filter.length);\n        prefixMatches.push(item);\n      } else {\n        const index = nameLowerCase.indexOf(filterLowerCase);\n        if (index > -1) {\n          item.link.innerHTML = makeLinkHtml(item, index, index + filter.length);\n          infixMatches.push(item);\n        }\n      }\n    }\n\n    for (const item of exactMatches.concat(prefixMatches).concat(infixMatches)) {\n      jumpList?.appendChild(item.link);\n    }\n  } else {\n    if (!jumpListItems || jumpListItems.length === 0) {\n      const msg = document.createElement('i');\n      msg.innerHTML = 'There are no identifiers on this page.';\n      jumpList?.appendChild(msg);\n    }\n    // No filter set; display all items in their existing order.\n    for (const item of jumpListItems ?? []) {\n      item.link.innerHTML = item.name + ' <i>' + item.kind + '</i>';\n      jumpList?.appendChild(item.link);\n    }\n  }\n\n  if (jumpBody) {\n    jumpBody.scrollTop = 0;\n  }\n  if (jumpListItems?.length && jumpList && jumpList.children.length > 0) {\n    setActiveJumpItem(0);\n  }\n}\n\n// Set the active jump item to n.\nfunction setActiveJumpItem(n: number) {\n  const cs = jumpList?.children as HTMLCollectionOf<HTMLElement> | null | undefined;\n  if (!cs || !jumpBody) {\n    return;\n  }\n  if (activeJumpItem >= 0) {\n    cs[activeJumpItem].classList.remove('JumpDialog-active');\n  }\n  if (n >= cs.length) {\n    n = cs.length - 1;\n  }\n  if (n >= 0) {\n    cs[n].classList.add('JumpDialog-active');\n\n    // Scroll so the active item is visible.\n    // For some reason cs[n].scrollIntoView() doesn't behave as I'd expect:\n    // it moves the entire dialog box in the viewport.\n\n    // Get the top and bottom of the active item relative to jumpBody.\n    const activeTop = cs[n].offsetTop - cs[0].offsetTop;\n    const activeBottom = activeTop + cs[n].clientHeight;\n    if (activeTop < jumpBody.scrollTop) {\n      // Off the top; scroll up.\n      jumpBody.scrollTop = activeTop;\n    } else if (activeBottom > jumpBody.scrollTop + jumpBody.clientHeight) {\n      // Off the bottom; scroll down.\n      jumpBody.scrollTop = activeBottom - jumpBody.clientHeight;\n    }\n  }\n  activeJumpItem = n;\n}\n\n// Increment the activeJumpItem by delta.\nfunction incActiveJumpItem(delta: number) {\n  if (activeJumpItem < 0) {\n    return;\n  }\n  let n = activeJumpItem + delta;\n  if (n < 0) {\n    n = 0;\n  }\n  setActiveJumpItem(n);\n}\n\n// Pressing a key in the filter updates the list (if the filter actually changed).\njumpFilter?.addEventListener('keyup', function () {\n  if (jumpFilter.value.toUpperCase() != lastFilterValue.toUpperCase()) {\n    updateJumpList(jumpFilter.value);\n  }\n});\n\n// Pressing enter in the filter selects the first element in the list.\njumpFilter?.addEventListener('keydown', function (event) {\n  const upArrow = 38;\n  const downArrow = 40;\n  const enterKey = 13;\n  switch (event.which) {\n    case upArrow:\n      incActiveJumpItem(-1);\n      event.preventDefault();\n      break;\n    case downArrow:\n      incActiveJumpItem(1);\n      event.preventDefault();\n      break;\n    case enterKey:\n      if (activeJumpItem >= 0) {\n        if (jumpList) {\n          (jumpList.children[activeJumpItem] as HTMLElement).click();\n        }\n      }\n      break;\n  }\n});\n\nconst shortcutsDialog = document.querySelector<HTMLDialogElement>('.ShortcutsDialog');\nif (shortcutsDialog && !shortcutsDialog.showModal) {\n  loadPolyfill().then(({ default: dialogPolyfill }) => {\n    dialogPolyfill.registerDialog(shortcutsDialog);\n  });\n}\n\n// Keyboard shortcuts:\n// - Pressing '/' focuses the search box\n// - Pressing 'f' or 'F' opens the jump-to-identifier dialog.\n// - Pressing '?' opens up the shortcut dialog.\n// Ignore a keypress if a dialog is already open, or if it is pressed on a\n// component that wants to consume it.\ndocument.addEventListener('keypress', function (e) {\n  if (jumpDialog?.open || shortcutsDialog?.open) {\n    return;\n  }\n  const target = e.target as HTMLElement | null;\n  const t = target?.tagName;\n  if (t == 'INPUT' || t == 'SELECT' || t == 'TEXTAREA') {\n    return;\n  }\n  if (target?.contentEditable == 'true') {\n    return;\n  }\n  if (e.metaKey || e.ctrlKey) {\n    return;\n  }\n  const ch = String.fromCharCode(e.which);\n  switch (ch) {\n    case 'f':\n    case 'F':\n      e.preventDefault();\n      if (jumpFilter) {\n        jumpFilter.value = '';\n      }\n      jumpDialog?.showModal();\n      updateJumpList('');\n      break;\n    case '?':\n      shortcutsDialog?.showModal();\n      break;\n    case '/':\n      // Favoring the Firefox quick find feature over search input\n      // focus. See: https://github.com/golang/go/issues/41093.\n      if (searchInput && !window.navigator.userAgent.includes('Firefox')) {\n        e.preventDefault();\n        searchInput.focus();\n      }\n      break;\n  }\n});\n\nconst jumpOutlineInput = document.querySelector('.js-jumpToInput');\nif (jumpOutlineInput) {\n  jumpOutlineInput.addEventListener('click', () => {\n    if (jumpFilter) {\n      jumpFilter.value = '';\n    }\n    jumpDialog?.showModal();\n    updateJumpList('');\n  });\n}\n"],
+  "mappings": "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",
   "names": []
 }
diff --git a/content/static/js/jump.ts b/content/static/js/jump.ts
index 31cda93..aa2474f 100644
--- a/content/static/js/jump.ts
+++ b/content/static/js/jump.ts
@@ -163,7 +163,7 @@
   } else {
     if (!jumpListItems || jumpListItems.length === 0) {
       const msg = document.createElement('i');
-      msg.innerHTML = 'No jump items found.';
+      msg.innerHTML = 'There are no identifiers on this page.';
       jumpList?.appendChild(msg);
     }
     // No filter set; display all items in their existing order.