diff --git a/history/information.go b/history/information.go
index 5c39cbf..3d8342e 100644
--- a/history/information.go
+++ b/history/information.go
@@ -141,7 +141,7 @@ func (rev *Revision) asHistoryEntry(hyphaName string) (html string) {
author := ""
if rev.Username != "anon" {
author = fmt.Sprintf(`
- by %[2]s`, cfg.UserHypha, rev.Username)
+ by %[2]s`, cfg.UserHypha, rev.Username)
}
return fmt.Sprintf(`
diff --git a/static/default.css b/static/default.css
index 836784d..05941b4 100644
--- a/static/default.css
+++ b/static/default.css
@@ -312,31 +312,40 @@ kbd {
text-align: center;
}
-.dialog-wrap {
- position: fixed;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background-color: rgba(0, 0, 0, 0.3);
- overflow-y: auto;
-
- padding: 0 16px;
+.kbd-or {
+ opacity: .4;
}
.dialog {
- position: relative;
+ position: absolute;
+ top: 0;
+ left: 50%;
width: 100%;
- max-width: 400px;
+ max-width: 700px;
margin: 96px auto;
padding: 24px;
+ transform: translate(-50%, 0);
background-color: #fff;
border-radius: 4px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}
+.dialog-backdrop {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0, 0, 0, 0.3);
+}
+
+.dialog__header {
+ position: relative;
+ grid-column: 1 / -1;
+}
+
.dialog__title {
margin: 0;
font-size: 1.5em;
@@ -347,7 +356,7 @@ kbd {
display: block;
top: 0;
right: 0;
- margin: 16px;
+ margin: 0;
padding: 8px;
border: none;
background: url(/static/icon/x.svg) no-repeat 8px 8px / 16px 16px;
@@ -360,17 +369,23 @@ kbd {
opacity: .7;
}
+.shortcuts-help .dialog__content {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ grid-column-gap: 32px;
+}
+
.shortcuts-group-heading {
margin: 1em 0 0.5em;
font-size: 1.2em;
}
-.shortcuts-group {
+.shortcuts-list {
margin: 0;
padding: 0;
}
-.shortcuts-group + .shortcuts-group {
+.shortcuts-list + .shortcuts-list {
margin-top: 1.5em;
}
diff --git a/static/shortcuts.js b/static/shortcuts.js
index beaa088..4eaedcd 100644
--- a/static/shortcuts.js
+++ b/static/shortcuts.js
@@ -1,6 +1,10 @@
-class Shortcut {
- // turns the given event into a string representation of it.
- static fromEvent(event) {
+(() => {
+ const $ = document.querySelector.bind(document);
+ const $$ = (...args) => Array.prototype.slice.call(document.querySelectorAll(...args));
+
+ const isMac = /Macintosh/.test(window.navigator.userAgent);
+
+ function keyEventToShortcut(event) {
let elideShift = event.key.toUpperCase() === event.key && event.shiftKey;
return (event.ctrlKey ? 'Ctrl+' : '') +
(event.altKey ? 'Alt+' : '') +
@@ -9,11 +13,9 @@ class Shortcut {
(event.key === ',' ? 'Comma' : event.key === ' ' ? 'Space' : event.key);
}
- // Some keys look better with cool symbols instead of their long and boring names.
- static prettify(shortcut, isMac) {
+ function prettifyShortcut(shortcut) {
let keys = shortcut.split('+');
- // Uh it places the cmd sign before the letter to follow the Mac conventions, I guess.
if (isMac) {
let cmdIdx = keys.indexOf('Meta');
if (cmdIdx !== -1 && keys.length - cmdIdx > 2) {
@@ -24,52 +26,39 @@ class Shortcut {
}
let lastKey = keys[keys.length - 1];
- // Uhh add Shift if the letter is uppercase??
if (!keys.includes('Shift') && lastKey.toUpperCase() === lastKey && lastKey.toLowerCase() !== lastKey) {
keys.splice(keys.length - 1, 0, 'Shift');
}
- return keys.map((key, i) => {
- // If last element and there is more than one element and it's a letter
- if (i === keys.length - 1 && i > 0 && key.length === 1) {
- // Show in upper case. ⌘K looks better ⌘k, no doubt.
- key = key.toUpperCase();
+ for (let i = 0; i < keys.length; i++) {
+ if (isMac) {
+ switch (keys[i]) {
+ case 'Ctrl': keys[i] = '⌃'; break;
+ case 'Alt': keys[i] = '⌥'; break;
+ case 'Shift': keys[i] = '⇧'; break;
+ case 'Meta': keys[i] = '⌘'; break;
+ }
}
- return `${Shortcut.symbolifyKey(key, isMac)}`;
- }).join(isMac ? '' : ' + ');
- }
-
- static symbolifyKey(key, isMac) {
- if (isMac) {
- switch (key) {
- case 'Ctrl': return '⌃';
- case 'Alt': return '⌥';
- case 'Shift': return '⇧';
- case 'Meta': return '⌘';
+ if (i === keys.length - 1 && i > 0 && keys[i].length === 1) {
+ keys[i] = keys[i].toUpperCase();
}
+
+ switch (keys[i]) {
+ case 'ArrowLeft': keys[i] = '←'; break;
+ case 'ArrowRight': keys[i] = '→'; break;
+ case 'ArrowUp': keys[i] = '↑'; break;
+ case 'ArrowDown': keys[i] = '↓'; break;
+ case 'Comma': keys[i] = ','; break;
+ case 'Enter': keys[i] = '↩'; break;
+ case ' ': keys[i] = 'Space'; break;
+ }
+
+ keys[i] = `${keys[i]}`;
}
- switch (key) {
- case 'ArrowLeft': return '←';
- case 'ArrowRight': return '→';
- case 'ArrowUp': return '↑';
- case 'ArrowDown': return '↓';
- case 'Comma': return ',';
- case 'Enter': return '↩';
- case ' ': return 'Space';
- }
- return key
+ return keys.join(isMac ? '' : ' + ');
}
-}
-
-(() => {
- const $ = document.querySelector.bind(document);
- const $$ = (...args) => Array.prototype.slice.call(document.querySelectorAll(...args));
-
- // Some things look different on Mac.
- // Note that the ⌘ command key is called Meta in JS for some reason.
- const isMac = /Macintosh/.test(window.navigator.userAgent);
function isTextField(element) {
let name = element.nodeName.toLowerCase();
@@ -81,29 +70,31 @@ class Shortcut {
let notTextField = event => !(event.target instanceof Node && isTextField(event.target));
- // The whole shortcut table for current page. It is used for generating the dialog.
let allShortcuts = [];
- // Temporary variable for building a shortcut group.
let shortcutsGroup = null;
- // Advanced stuff.
class ShortcutHandler {
- constructor(element, filter = () => true) {
+ constructor(element, override, filter = () => true) {
this.element = element;
this.map = {};
this.active = this.map;
+ this.override = override;
this.filter = filter;
this.timeout = null;
this.handleKeyDown = this.handleKeyDown.bind(this);
this.resetActive = this.resetActive.bind(this);
+ this.addEventListeners();
+ }
+
+ addEventListeners() {
this.element.addEventListener('keydown', this.handleKeyDown);
}
- add(text, action, description = null) {
- let shortcuts = text.split(',').map(shortcut => shortcut.trim().split(' '));
+ add(text, action, description = null, shownInHelp = true) {
+ let shortcuts = text.trim().split(',').map(shortcut => shortcut.trim().split(' '));
- if (shortcutsGroup) {
+ if (shortcutsGroup && shownInHelp) {
shortcutsGroup.push({
action,
shortcut: text,
@@ -131,20 +122,48 @@ class Shortcut {
}
}
- groupStart() {
+ group(...args) {
+ if (typeof args[0] === 'string') this.fakeItem(args.shift());
shortcutsGroup = [];
- }
- groupEnd() {
+ args[0].bind(this)();
+
if (shortcutsGroup && shortcutsGroup.length) allShortcuts.push(shortcutsGroup);
shortcutsGroup = null;
}
- // A dirty and shameful hack for inserting non-generated entries into the table.
+ bindElement(shortcut, element, ...other) {
+ element = typeof element === 'string' ? $(element) : element;
+ if (!element) return;
+ this.add(shortcut, () => {
+ if (isTextField(element)) {
+ element.focus();
+ } else {
+ element.click();
+ }
+ }, ...other);
+ }
+
+ bindLink(shortcut, link, ...other) {
+ this.add(shortcut, () => window.location.href = link, ...other);
+ }
+
+ bindCollection(prefix, elements, collectionDescription, itemDescription) {
+ this.fakeItem(prefix + ' 1 – 9', collectionDescription);
+
+ if (typeof elements === 'string') {
+ elements = $$(elements);
+ } else if (Array.isArray(elements)) {
+ elements = elements.map(el => typeof el === 'string' ? $(el) : el);
+ }
+
+ for (let i = 1; i <= elements.length && i < 10; i++) {
+ this.bindElement(`${prefix} ${i}`, elements[i-1], `${itemDescription} #${i}`, false);
+ }
+ }
+
fakeItem(shortcut, description = null) {
- // So it's a boolean, right?
let list = shortcutsGroup || allShortcuts;
- // And we push something into a boolean. I give up.
list.push({
shortcut: description ? shortcut : null,
description: description || shortcut,
@@ -156,7 +175,7 @@ class Shortcut {
if (['Control', 'Alt', 'Shift', 'Meta'].includes(event.key)) return;
if (!this.filter(event)) return;
- let shortcut = Shortcut.fromEvent(event);
+ let shortcut = keyEventToShortcut(event);
if (!this.active[shortcut]) {
this.resetActive();
@@ -165,7 +184,9 @@ class Shortcut {
this.active = this.active[shortcut];
if (this.active.action) {
+ event.stopPropagation();
this.active.action(event);
+ if (this.override) event.preventDefault();
this.resetActive();
return;
}
@@ -183,62 +204,46 @@ class Shortcut {
}
}
- function bindElementFactory(handler) {
- return (shortcut, element, ...other) => {
- element = typeof element === 'string' ? $(element) : element;
- if (!element) return;
- handler.add(shortcut, () => {
- if (isTextField(element)) {
- element.focus();
- } else {
- element.click();
- }
- }, ...other);
- };
- }
+ class ShortcutsHelpDialog {
+ constructor() {
+ let template = $('#dialog-template');
+ let clonedTemplate = template.content.cloneNode(true);
+ this.backdrop = clonedTemplate.children[0];
+ this.dialog = clonedTemplate.children[1];
- function bindLinkFactory(handler) {
- return (shortcut, link, ...other) => handler.add(shortcut, () => window.location.href = link, ...other);
- }
+ this.dialog.classList.add('shortcuts-help');
+ this.dialog.hidden = true;
+ this.backdrop.hidden = true;
- let prevActiveElement = null;
- let shortcutsListDialog = null;
+ document.body.appendChild(this.backdrop);
+ document.body.appendChild(this.dialog);
- function openShortcutsReference() {
- if (!shortcutsListDialog) { // I guess the dialog is reused for second and subsequent invocations.
- let wrap = document.createElement('div');
- wrap.className = 'dialog-wrap';
- shortcutsListDialog = wrap;
+ this.close = this.close.bind(this);
- let dialog = document.createElement('div');
- dialog.className = 'dialog shortcuts-modal';
- dialog.tabIndex = 0;
- wrap.appendChild(dialog);
+ this.dialog.querySelector('.dialog__title').textContent = 'List of shortcuts';
+ this.dialog.querySelector('.dialog__close-button').addEventListener('click', this.close);
+ this.backdrop.addEventListener('click', this.close);
- let dialogHeader = document.createElement('div');
- dialogHeader.className = 'dialog__header';
- dialog.appendChild(dialogHeader);
+ this.shortcuts = new ShortcutHandler(this.dialog, false);
+ this.shortcuts.add('Escape', this.close, null, false);
- let title = document.createElement('h1');
- title.className = 'dialog__title';
- title.textContent = 'List of shortcuts';
- dialogHeader.appendChild(title);
-
- let closeButton = document.createElement('button');
- closeButton.className = 'dialog__close-button';
- closeButton.setAttribute('aria-label', 'Close this dialog'); // a11y gang
- dialogHeader.appendChild(closeButton);
+ let shortcutsGroup;
+ let shortcutsGroupTemplate = document.createElement('div');
+ shortcutsGroupTemplate.className = 'shortcuts-group';
for (let item of allShortcuts) {
if (item.description && !item.shortcut) {
+ shortcutsGroup = shortcutsGroupTemplate.cloneNode();
+ this.dialog.querySelector('.dialog__content').appendChild(shortcutsGroup);
+
let heading = document.createElement('h2');
heading.className = 'shortcuts-group-heading';
heading.textContent = item.description;
- dialog.appendChild(heading);
+ shortcutsGroup.appendChild(heading);
} else {
let list = document.createElement('ul');
- list.className = 'shortcuts-group';
+ list.className = 'shortcuts-list';
for (let shortcut of item) {
let listItem = document.createElement('li');
@@ -253,137 +258,108 @@ class Shortcut {
let shortcutColumn = document.createElement('div');
shortcutColumn.className = 'shortcut-row__keys';
shortcutColumn.innerHTML = shortcut.shortcut.split(',')
- .map(shortcuts => shortcuts.trim().split(' ').map((sc) => Shortcut.prettify(sc, isMac)).join(' '))
- .join(' or ');
+ .map(shortcuts => shortcuts.trim().split(' ').map(prettifyShortcut).join(' '))
+ .join(' or ');
listItem.appendChild(shortcutColumn);
}
- dialog.appendChild(list);
+ shortcutsGroup.appendChild(list);
}
}
-
- let handleClose = (event) => {
- event.preventDefault();
- event.stopPropagation();
- closeShortcutsReference();
- };
-
- let dialogShortcuts = new ShortcutHandler(dialog, notTextField);
-
- dialogShortcuts.add('Escape', handleClose);
- closeButton.addEventListener('click', handleClose);
- wrap.addEventListener('click', handleClose);
-
- dialog.addEventListener('click', event => event.stopPropagation());
-
- document.body.appendChild(wrap);
}
- document.body.overflow = 'hidden';
- shortcutsListDialog.hidden = false;
- prevActiveElement = document.activeElement;
- shortcutsListDialog.children[0].focus();
- }
+ open() {
+ this.prevActiveElement = document.activeElement;
- function closeShortcutsReference() {
- if (shortcutsListDialog) {
+ document.body.overflow = 'hidden';
+ this.backdrop.hidden = false;
+ this.dialog.hidden = false;
+ this.dialog.focus();
+ }
+
+ close() {
document.body.overflow = '';
- shortcutsListDialog.hidden = true;
+ this.backdrop.hidden = true;
+ this.dialog.hidden = true;
- if (prevActiveElement) {
- prevActiveElement.focus();
- prevActiveElement = null;
+ if (this.prevActiveElement) {
+ this.prevActiveElement.focus();
+ this.prevActiveElement = null;
}
}
}
window.addEventListener('load', () => {
- let globalShortcuts = new ShortcutHandler(document, notTextField);
+ let helpDialog = null;
+ let openHelp = () => {
+ if (!helpDialog) helpDialog = new ShortcutsHelpDialog();
+ helpDialog.open();
+ };
- // Global shortcuts
+ let onEditPage = typeof editTextarea !== 'undefined';
- let bindElement = bindElementFactory(globalShortcuts);
- let bindLink = bindLinkFactory(globalShortcuts);
+ // Global shortcuts work everywhere.
+ let globalShortcuts = new ShortcutHandler(document, false);
+ globalShortcuts.add('?, ' + (isMac ? 'Meta+/' : 'Ctrl+/'), openHelp);
- // * Common shortcuts
- globalShortcuts.fakeItem('Common');
+ // Page shortcuts work everywhere except on text fields.
+ let pageShortcuts = new ShortcutHandler(document, false, notTextField);
+ pageShortcuts.add('?', openHelp, null, false);
- // Nice indentation here
- globalShortcuts.groupStart();
- globalShortcuts.fakeItem('g 1 – 9', 'First 9 header links');
- bindLink('g h', '/', 'Home');
- bindLink('g l', '/list/', 'List of hyphae');
- bindLink('g r', '/recent-changes/', 'Recent changes');
- bindElement('g u', '.header-links__entry_user .header-links__link', 'Your profile′s hypha');
- globalShortcuts.groupEnd();
+ // Common shortcuts
+ pageShortcuts.group('Common', function () {
+ this.bindCollection('g', '.header-links__link', 'First 9 header links', 'Header link');
+ this.bindLink('g h', '/', 'Home');
+ this.bindLink('g l', '/list/', 'List of hyphae');
+ this.bindLink('g r', '/recent-changes/', 'Recent changes');
+ this.bindElement('g u', '.header-links__entry_user .header-links__link', 'Your profile′s hypha');
+ });
- let headerLinks = $$('.header-links__link');
- for (let i = 1; i <= headerLinks.length && i < 10; i++) {
- bindElement(`g ${i}`, headerLinks[i-1], `Header link #${i}`);
- }
+ if (!onEditPage) {
+ // Hypha shortcuts
+ pageShortcuts.group('Hypha', function () {
+ this.bindCollection('', 'article .wikilink', 'First 9 hypha′s links', 'Hypha link');
+ this.bindElement('p, Alt+ArrowLeft, Ctrl+Alt+ArrowLeft', '.prevnext__prev', 'Next hypha');
+ this.bindElement('n, Alt+ArrowRight, Ctrl+Alt+ArrowRight', '.prevnext__next', 'Previous hypha');
+ this.bindElement('s, Alt+ArrowUp, Ctrl+Alt+ArrowUp', $$('.navi-title a').slice(1, -1).slice(-1)[0], 'Parent hypha');
+ this.bindElement('c, Alt+ArrowDown, Ctrl+Alt+ArrowDown', '.subhyphae__link', 'First child hypha');
- // * Hypha shortcuts
- if (typeof editTextarea === 'undefined') {
- globalShortcuts.fakeItem('Hypha');
+ this.bindElement('v', '.hypha-tabs__link[href^="/hypha/"]', 'Go to hypha′s page');
+ this.bindElement('e, Ctrl+Enter', '.hypha-tabs__link[href^="/edit/"]', 'Edit this hypha');
+ this.bindElement('a', '.hypha-tabs__link[href^="/attachment/"]', 'Go to attachment');
+ this.bindElement('h', '.hypha-tabs__link[href^="/history/"]', 'Go to history');
+ this.bindElement('r', '.hypha-tabs__link[href^="/rename-ask/"]', 'Rename this hypha');
+ });
- globalShortcuts.groupStart();
- globalShortcuts.fakeItem('1 – 9', 'First 9 hypha′s links');
- bindElement('p, Alt+ArrowLeft, Ctrl+Alt+ArrowLeft', '.prevnext__prev', 'Next hypha');
- bindElement('n, Alt+ArrowRight, Ctrl+Alt+ArrowRight', '.prevnext__next', 'Previous hypha');
- bindElement('s, Alt+ArrowUp, Ctrl+Alt+ArrowUp', $$('.navi-title a').slice(1, -1).slice(-1)[0], 'Parent hypha');
- bindElement('c, Alt+ArrowDown, Ctrl+Alt+ArrowDown', '.subhyphae__link', 'First child hypha');
- bindElement('e, Ctrl+Enter', '.hypha-tabs__link[href^="/edit/"]', 'Edit this hypha');
- globalShortcuts.groupEnd();
-
- let hyphaLinks = $$('article .wikilink');
- for (let i = 1; i <= hyphaLinks.length && i < 10; i++) {
- bindElement(i.toString(), hyphaLinks[i-1], `Hypha link #${i}`);
- }
- }
-
- // * Editor shortcuts
- if (typeof editTextarea !== 'undefined') {
- let editorShortcuts = new ShortcutHandler(editTextarea);
- let bindElement = bindElementFactory(editorShortcuts);
+ } else {
+ // Hypha editor shortcuts. These work only on editor's text area.
+ let editorShortcuts = new ShortcutHandler(editTextarea, true);
let shortcuts = [
- // Inspired by MS Word, Pages, Google Docs and Telegram desktop clients.
- // And by myself, too.
-
- // Win+Linux Mac Action Description
- ['Ctrl+b', 'Meta+b', wrapBold, 'Format: Bold'],
- ['Ctrl+i', 'Meta+i', wrapItalic, 'Format: Italic'],
- ['Ctrl+M', 'Meta+Shift+m', wrapMonospace, 'Format: Monospaced'],
- ['Ctrl+I', 'Meta+Shift+i', wrapHighlighted, 'Format: Highlight'],
- ['Ctrl+.', 'Meta+.', wrapLifted, 'Format: Superscript'],
- ['Ctrl+Comma', 'Meta+Comma', wrapLowered, 'Format: Subscript'],
- // Strikethrough conflicts with 1Password on my machine but
- // I'm probably the only Mycorrhiza user who uses 1Password. -handlerug
- ['Ctrl+X', 'Meta+Shift+x', wrapStrikethrough, 'Format: Strikethrough'],
- ['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'],
+ // Win+Linux Mac Action Description
+ ['Ctrl+b', 'Meta+b', wrapBold, 'Format: Bold'],
+ ['Ctrl+i', 'Meta+i', wrapItalic, 'Format: Italic'],
+ ['Ctrl+M', 'Meta+Shift+m', wrapMonospace, 'Format: Monospaced'],
+ ['Ctrl+I', 'Meta+Shift+i', wrapHighlighted, 'Format: Highlight'],
+ ['Ctrl+.', 'Meta+.', wrapLifted, 'Format: Superscript'],
+ ['Ctrl+Comma', 'Meta+Comma', wrapLowered, 'Format: Subscript'],
+ ['Ctrl+X', 'Meta+Shift+x', wrapStrikethrough, 'Format: Strikethrough'],
+ ['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'],
];
- editorShortcuts.fakeItem('Editor');
-
- editorShortcuts.groupStart();
- for (let shortcut of shortcuts) {
- if (isMac) {
- editorShortcuts.add(shortcut[1], ...shortcut.slice(2))
- } else {
- editorShortcuts.add(shortcut[0], ...shortcut.slice(2))
+ editorShortcuts.group('Editor', function () {
+ for (let shortcut of shortcuts) {
+ if (isMac) {
+ this.add(shortcut[1], ...shortcut.slice(2))
+ } else {
+ this.add(shortcut[0], ...shortcut.slice(2))
+ }
}
- }
- editorShortcuts.groupEnd();
+ });
- editorShortcuts.groupStart();
- bindElement(isMac ? 'Meta+Enter' : 'Ctrl+Enter', $('.edit-form__save'), 'Save changes');
- editorShortcuts.groupEnd();
-
- // Help shortcut
- editorShortcuts.add(isMac ? 'Meta+/' : 'Ctrl+/', openShortcutsReference);
+ editorShortcuts.group(function () {
+ this.bindElement(isMac ? 'Meta+Enter' : 'Ctrl+Enter', $('.edit-form__save'), 'Save changes');
+ });
}
-
- // * Meta shortcuts
- globalShortcuts.add('?', openShortcutsReference);
});
})();
diff --git a/views/mutators.qtpl b/views/mutators.qtpl
index 0e15f55..81807e4 100644
--- a/views/mutators.qtpl
+++ b/views/mutators.qtpl
@@ -83,7 +83,7 @@
- Cancel
+ Cancel
{%s= Toolbar(user.FromRequest(rq)) %}
@@ -106,7 +106,7 @@
- Cancel
+ Cancel
Note that the hypha is not saved yet. You can preview the changes ↓
{%s= renderedPage %}
diff --git a/views/mutators.qtpl.go b/views/mutators.qtpl.go
index 8d513a7..f0d0363 100644
--- a/views/mutators.qtpl.go
+++ b/views/mutators.qtpl.go
@@ -210,8 +210,8 @@ func StreamEditHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, text
- Cancel
@@ -300,8 +300,8 @@ func StreamPreviewHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, t
- Cancel
diff --git a/views/nav.qtpl b/views/nav.qtpl
index eaad97e..90f6d22 100644
--- a/views/nav.qtpl
+++ b/views/nav.qtpl
@@ -11,7 +11,7 @@ type navEntry struct {
title string
}
var navEntries = []navEntry{
- {"page", "Hypha"},
+ {"hypha", "Hypha"},
{"edit", "Edit"},
{"attachment", "Attachment"},
{"history", "History"},
diff --git a/views/nav.qtpl.go b/views/nav.qtpl.go
index 1011440..331b342 100644
--- a/views/nav.qtpl.go
+++ b/views/nav.qtpl.go
@@ -41,7 +41,7 @@ type navEntry struct {
}
var navEntries = []navEntry{
- {"page", "Hypha"},
+ {"hypha", "Hypha"},
{"edit", "Edit"},
{"attachment", "Attachment"},
{"history", "History"},
diff --git a/views/readers.qtpl b/views/readers.qtpl
index 7d22dda..6f2b1d3 100644
--- a/views/readers.qtpl
+++ b/views/readers.qtpl
@@ -80,7 +80,7 @@ If `contents` == "", a helpful message is shown instead.
relatives, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name)
u := user.FromRequest(rq)
%}
-{%= NavHTML(rq, h.Name, "page") %}
+{%= NavHTML(rq, h.Name, "hypha") %}
diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go
index fd58941..ef8d7d1 100644
--- a/views/readers.qtpl.go
+++ b/views/readers.qtpl.go
@@ -241,7 +241,7 @@ func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hyph
qw422016.N().S(`
`)
//line views/readers.qtpl:83
- StreamNavHTML(qw422016, rq, h.Name, "page")
+ StreamNavHTML(qw422016, rq, h.Name, "hypha")
//line views/readers.qtpl:83
qw422016.N().S(`
diff --git a/views/stuff.qtpl b/views/stuff.qtpl
index 0e75d94..f0169d2 100644
--- a/views/stuff.qtpl
+++ b/views/stuff.qtpl
@@ -28,6 +28,17 @@
{%s= body %}
+
+
+
+
{%= omnipresentScripts() %}