1
0
mirror of https://github.com/osmarks/mycorrhiza.git synced 2025-03-06 11:38:19 +00:00

Merge branch 'master' into master

This commit is contained in:
handlerug 2021-06-14 14:27:28 +07:00 committed by GitHub
commit 679588abd5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 417 additions and 404 deletions

View File

@ -141,7 +141,7 @@ func (rev *Revision) asHistoryEntry(hyphaName string) (html string) {
author := "" author := ""
if rev.Username != "anon" { if rev.Username != "anon" {
author = fmt.Sprintf(` author = fmt.Sprintf(`
<span class="history-entry__author">by <a href="/page/%[1]s/%[2]s" rel="author">%[2]s</span>`, cfg.UserHypha, rev.Username) <span class="history-entry__author">by <a href="/hypha/%[1]s/%[2]s" rel="author">%[2]s</span>`, cfg.UserHypha, rev.Username)
} }
return fmt.Sprintf(` return fmt.Sprintf(`
<li class="history__entry"> <li class="history__entry">

View File

@ -312,31 +312,40 @@ kbd {
text-align: center; text-align: center;
} }
.dialog-wrap { .kbd-or {
position: fixed; opacity: .4;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.3);
overflow-y: auto;
padding: 0 16px;
} }
.dialog { .dialog {
position: relative; position: absolute;
top: 0;
left: 50%;
width: 100%; width: 100%;
max-width: 400px; max-width: 700px;
margin: 96px auto; margin: 96px auto;
padding: 24px; padding: 24px;
transform: translate(-50%, 0);
background-color: #fff; background-color: #fff;
border-radius: 4px; border-radius: 4px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); 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 { .dialog__title {
margin: 0; margin: 0;
font-size: 1.5em; font-size: 1.5em;
@ -347,7 +356,7 @@ kbd {
display: block; display: block;
top: 0; top: 0;
right: 0; right: 0;
margin: 16px; margin: 0;
padding: 8px; padding: 8px;
border: none; border: none;
background: url(/static/icon/x.svg) no-repeat 8px 8px / 16px 16px; background: url(/static/icon/x.svg) no-repeat 8px 8px / 16px 16px;
@ -360,17 +369,23 @@ kbd {
opacity: .7; opacity: .7;
} }
.shortcuts-help .dialog__content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
grid-column-gap: 32px;
}
.shortcuts-group-heading { .shortcuts-group-heading {
margin: 1em 0 0.5em; margin: 1em 0 0.5em;
font-size: 1.2em; font-size: 1.2em;
} }
.shortcuts-group { .shortcuts-list {
margin: 0; margin: 0;
padding: 0; padding: 0;
} }
.shortcuts-group + .shortcuts-group { .shortcuts-list + .shortcuts-list {
margin-top: 1.5em; margin-top: 1.5em;
} }

View File

@ -1,6 +1,10 @@
class Shortcut { (() => {
// turns the given event into a string representation of it. const $ = document.querySelector.bind(document);
static fromEvent(event) { 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; let elideShift = event.key.toUpperCase() === event.key && event.shiftKey;
return (event.ctrlKey ? 'Ctrl+' : '') + return (event.ctrlKey ? 'Ctrl+' : '') +
(event.altKey ? 'Alt+' : '') + (event.altKey ? 'Alt+' : '') +
@ -9,11 +13,9 @@ class Shortcut {
(event.key === ',' ? 'Comma' : event.key === ' ' ? 'Space' : event.key); (event.key === ',' ? 'Comma' : event.key === ' ' ? 'Space' : event.key);
} }
// Some keys look better with cool symbols instead of their long and boring names. function prettifyShortcut(shortcut) {
static prettify(shortcut, isMac) {
let keys = shortcut.split('+'); let keys = shortcut.split('+');
// Uh it places the cmd sign before the letter to follow the Mac conventions, I guess.
if (isMac) { if (isMac) {
let cmdIdx = keys.indexOf('Meta'); let cmdIdx = keys.indexOf('Meta');
if (cmdIdx !== -1 && keys.length - cmdIdx > 2) { if (cmdIdx !== -1 && keys.length - cmdIdx > 2) {
@ -24,52 +26,39 @@ class Shortcut {
} }
let lastKey = keys[keys.length - 1]; let lastKey = keys[keys.length - 1];
// Uhh add Shift if the letter is uppercase??
if (!keys.includes('Shift') && lastKey.toUpperCase() === lastKey && lastKey.toLowerCase() !== lastKey) { if (!keys.includes('Shift') && lastKey.toUpperCase() === lastKey && lastKey.toLowerCase() !== lastKey) {
keys.splice(keys.length - 1, 0, 'Shift'); keys.splice(keys.length - 1, 0, 'Shift');
} }
return keys.map((key, i) => { for (let i = 0; i < keys.length; 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();
}
return `<kbd>${Shortcut.symbolifyKey(key, isMac)}</kbd>`;
}).join(isMac ? '' : ' + ');
}
static symbolifyKey(key, isMac) {
if (isMac) { if (isMac) {
switch (key) { switch (keys[i]) {
case 'Ctrl': return '⌃'; case 'Ctrl': keys[i] = '⌃'; break;
case 'Alt': return '⌥'; case 'Alt': keys[i] = '⌥'; break;
case 'Shift': return '⇧'; case 'Shift': keys[i] = '⇧'; break;
case 'Meta': return '⌘'; case 'Meta': keys[i] = '⌘'; break;
} }
} }
switch (key) { if (i === keys.length - 1 && i > 0 && keys[i].length === 1) {
case 'ArrowLeft': return '←'; keys[i] = keys[i].toUpperCase();
case 'ArrowRight': return '→';
case 'ArrowUp': return '↑';
case 'ArrowDown': return '↓';
case 'Comma': return ',';
case 'Enter': return '↩';
case ' ': return 'Space';
}
return key
}
} }
(() => { switch (keys[i]) {
const $ = document.querySelector.bind(document); case 'ArrowLeft': keys[i] = '←'; break;
const $$ = (...args) => Array.prototype.slice.call(document.querySelectorAll(...args)); 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;
}
// Some things look different on Mac. keys[i] = `<kbd>${keys[i]}</kbd>`;
// Note that the ⌘ command key is called Meta in JS for some reason. }
const isMac = /Macintosh/.test(window.navigator.userAgent);
return keys.join(isMac ? '' : ' + ');
}
function isTextField(element) { function isTextField(element) {
let name = element.nodeName.toLowerCase(); let name = element.nodeName.toLowerCase();
@ -81,29 +70,31 @@ class Shortcut {
let notTextField = event => !(event.target instanceof Node && isTextField(event.target)); 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 = []; let allShortcuts = [];
// Temporary variable for building a shortcut group.
let shortcutsGroup = null; let shortcutsGroup = null;
// Advanced stuff.
class ShortcutHandler { class ShortcutHandler {
constructor(element, filter = () => true) { constructor(element, override, filter = () => true) {
this.element = element; this.element = element;
this.map = {}; this.map = {};
this.active = this.map; this.active = this.map;
this.override = override;
this.filter = filter; this.filter = filter;
this.timeout = null; this.timeout = null;
this.handleKeyDown = this.handleKeyDown.bind(this); this.handleKeyDown = this.handleKeyDown.bind(this);
this.resetActive = this.resetActive.bind(this); this.resetActive = this.resetActive.bind(this);
this.addEventListeners();
}
addEventListeners() {
this.element.addEventListener('keydown', this.handleKeyDown); this.element.addEventListener('keydown', this.handleKeyDown);
} }
add(text, action, description = null) { add(text, action, description = null, shownInHelp = true) {
let shortcuts = text.split(',').map(shortcut => shortcut.trim().split(' ')); let shortcuts = text.trim().split(',').map(shortcut => shortcut.trim().split(' '));
if (shortcutsGroup) { if (shortcutsGroup && shownInHelp) {
shortcutsGroup.push({ shortcutsGroup.push({
action, action,
shortcut: text, shortcut: text,
@ -131,20 +122,48 @@ class Shortcut {
} }
} }
groupStart() { group(...args) {
if (typeof args[0] === 'string') this.fakeItem(args.shift());
shortcutsGroup = []; shortcutsGroup = [];
}
groupEnd() { args[0].bind(this)();
if (shortcutsGroup && shortcutsGroup.length) allShortcuts.push(shortcutsGroup); if (shortcutsGroup && shortcutsGroup.length) allShortcuts.push(shortcutsGroup);
shortcutsGroup = null; 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) { fakeItem(shortcut, description = null) {
// So it's a boolean, right?
let list = shortcutsGroup || allShortcuts; let list = shortcutsGroup || allShortcuts;
// And we push something into a boolean. I give up.
list.push({ list.push({
shortcut: description ? shortcut : null, shortcut: description ? shortcut : null,
description: description || shortcut, description: description || shortcut,
@ -156,7 +175,7 @@ class Shortcut {
if (['Control', 'Alt', 'Shift', 'Meta'].includes(event.key)) return; if (['Control', 'Alt', 'Shift', 'Meta'].includes(event.key)) return;
if (!this.filter(event)) return; if (!this.filter(event)) return;
let shortcut = Shortcut.fromEvent(event); let shortcut = keyEventToShortcut(event);
if (!this.active[shortcut]) { if (!this.active[shortcut]) {
this.resetActive(); this.resetActive();
@ -165,7 +184,9 @@ class Shortcut {
this.active = this.active[shortcut]; this.active = this.active[shortcut];
if (this.active.action) { if (this.active.action) {
event.stopPropagation();
this.active.action(event); this.active.action(event);
if (this.override) event.preventDefault();
this.resetActive(); this.resetActive();
return; return;
} }
@ -183,62 +204,46 @@ class Shortcut {
} }
} }
function bindElementFactory(handler) { class ShortcutsHelpDialog {
return (shortcut, element, ...other) => { constructor() {
element = typeof element === 'string' ? $(element) : element; let template = $('#dialog-template');
if (!element) return; let clonedTemplate = template.content.cloneNode(true);
handler.add(shortcut, () => { this.backdrop = clonedTemplate.children[0];
if (isTextField(element)) { this.dialog = clonedTemplate.children[1];
element.focus();
} else {
element.click();
}
}, ...other);
};
}
function bindLinkFactory(handler) { this.dialog.classList.add('shortcuts-help');
return (shortcut, link, ...other) => handler.add(shortcut, () => window.location.href = link, ...other); this.dialog.hidden = true;
} this.backdrop.hidden = true;
let prevActiveElement = null; document.body.appendChild(this.backdrop);
let shortcutsListDialog = null; document.body.appendChild(this.dialog);
function openShortcutsReference() { this.close = this.close.bind(this);
if (!shortcutsListDialog) { // I guess the dialog is reused for second and subsequent invocations.
let wrap = document.createElement('div');
wrap.className = 'dialog-wrap';
shortcutsListDialog = wrap;
let dialog = document.createElement('div'); this.dialog.querySelector('.dialog__title').textContent = 'List of shortcuts';
dialog.className = 'dialog shortcuts-modal'; this.dialog.querySelector('.dialog__close-button').addEventListener('click', this.close);
dialog.tabIndex = 0; this.backdrop.addEventListener('click', this.close);
wrap.appendChild(dialog);
let dialogHeader = document.createElement('div'); this.shortcuts = new ShortcutHandler(this.dialog, false);
dialogHeader.className = 'dialog__header'; this.shortcuts.add('Escape', this.close, null, false);
dialog.appendChild(dialogHeader);
let title = document.createElement('h1'); let shortcutsGroup;
title.className = 'dialog__title'; let shortcutsGroupTemplate = document.createElement('div');
title.textContent = 'List of shortcuts'; shortcutsGroupTemplate.className = 'shortcuts-group';
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);
for (let item of allShortcuts) { for (let item of allShortcuts) {
if (item.description && !item.shortcut) { if (item.description && !item.shortcut) {
shortcutsGroup = shortcutsGroupTemplate.cloneNode();
this.dialog.querySelector('.dialog__content').appendChild(shortcutsGroup);
let heading = document.createElement('h2'); let heading = document.createElement('h2');
heading.className = 'shortcuts-group-heading'; heading.className = 'shortcuts-group-heading';
heading.textContent = item.description; heading.textContent = item.description;
dialog.appendChild(heading); shortcutsGroup.appendChild(heading);
} else { } else {
let list = document.createElement('ul'); let list = document.createElement('ul');
list.className = 'shortcuts-group'; list.className = 'shortcuts-list';
for (let shortcut of item) { for (let shortcut of item) {
let listItem = document.createElement('li'); let listItem = document.createElement('li');
@ -253,103 +258,84 @@ class Shortcut {
let shortcutColumn = document.createElement('div'); let shortcutColumn = document.createElement('div');
shortcutColumn.className = 'shortcut-row__keys'; shortcutColumn.className = 'shortcut-row__keys';
shortcutColumn.innerHTML = shortcut.shortcut.split(',') shortcutColumn.innerHTML = shortcut.shortcut.split(',')
.map(shortcuts => shortcuts.trim().split(' ').map((sc) => Shortcut.prettify(sc, isMac)).join(' ')) .map(shortcuts => shortcuts.trim().split(' ').map(prettifyShortcut).join(' '))
.join(' or '); .join(' <span class="kbd-or">or</span> ');
listItem.appendChild(shortcutColumn); listItem.appendChild(shortcutColumn);
} }
dialog.appendChild(list); shortcutsGroup.appendChild(list);
}
} }
} }
let handleClose = (event) => { open() {
event.preventDefault(); this.prevActiveElement = document.activeElement;
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'; document.body.overflow = 'hidden';
shortcutsListDialog.hidden = false; this.backdrop.hidden = false;
prevActiveElement = document.activeElement; this.dialog.hidden = false;
shortcutsListDialog.children[0].focus(); this.dialog.focus();
} }
function closeShortcutsReference() { close() {
if (shortcutsListDialog) {
document.body.overflow = ''; document.body.overflow = '';
shortcutsListDialog.hidden = true; this.backdrop.hidden = true;
this.dialog.hidden = true;
if (prevActiveElement) { if (this.prevActiveElement) {
prevActiveElement.focus(); this.prevActiveElement.focus();
prevActiveElement = null; this.prevActiveElement = null;
} }
} }
} }
window.addEventListener('load', () => { 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); // Global shortcuts work everywhere.
let bindLink = bindLinkFactory(globalShortcuts); let globalShortcuts = new ShortcutHandler(document, false);
globalShortcuts.add('?, ' + (isMac ? 'Meta+/' : 'Ctrl+/'), openHelp);
// * Common shortcuts // Page shortcuts work everywhere except on text fields.
globalShortcuts.fakeItem('Common'); let pageShortcuts = new ShortcutHandler(document, false, notTextField);
pageShortcuts.add('?', openHelp, null, false);
// Nice indentation here // Common shortcuts
globalShortcuts.groupStart(); pageShortcuts.group('Common', function () {
globalShortcuts.fakeItem('g 1 9', 'First 9 header links'); this.bindCollection('g', '.header-links__link', 'First 9 header links', 'Header link');
bindLink('g h', '/', 'Home'); this.bindLink('g h', '/', 'Home');
bindLink('g l', '/list/', 'List of hyphae'); this.bindLink('g l', '/list/', 'List of hyphae');
bindLink('g r', '/recent-changes/', 'Recent changes'); this.bindLink('g r', '/recent-changes/', 'Recent changes');
bindElement('g u', '.header-links__entry_user .header-links__link', 'Your profiles hypha'); this.bindElement('g u', '.header-links__entry_user .header-links__link', 'Your profiles hypha');
globalShortcuts.groupEnd(); });
let headerLinks = $$('.header-links__link'); if (!onEditPage) {
for (let i = 1; i <= headerLinks.length && i < 10; i++) { // Hypha shortcuts
bindElement(`g ${i}`, headerLinks[i-1], `Header link #${i}`); pageShortcuts.group('Hypha', function () {
} this.bindCollection('', 'article .wikilink', 'First 9 hyphas 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 this.bindElement('v', '.hypha-tabs__link[href^="/hypha/"]', 'Go to hyphas page');
if (typeof editTextarea === 'undefined') { this.bindElement('e, Ctrl+Enter', '.hypha-tabs__link[href^="/edit/"]', 'Edit this hypha');
globalShortcuts.fakeItem('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(); } else {
globalShortcuts.fakeItem('1 9', 'First 9 hyphas links'); // Hypha editor shortcuts. These work only on editor's text area.
bindElement('p, Alt+ArrowLeft, Ctrl+Alt+ArrowLeft', '.prevnext__prev', 'Next hypha'); let editorShortcuts = new ShortcutHandler(editTextarea, true);
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);
let shortcuts = [ let shortcuts = [
// Inspired by MS Word, Pages, Google Docs and Telegram desktop clients.
// And by myself, too.
// Win+Linux Mac Action Description // Win+Linux Mac Action Description
['Ctrl+b', 'Meta+b', wrapBold, 'Format: Bold'], ['Ctrl+b', 'Meta+b', wrapBold, 'Format: Bold'],
['Ctrl+i', 'Meta+i', wrapItalic, 'Format: Italic'], ['Ctrl+i', 'Meta+i', wrapItalic, 'Format: Italic'],
@ -357,33 +343,23 @@ class Shortcut {
['Ctrl+I', 'Meta+Shift+i', wrapHighlighted, 'Format: Highlight'], ['Ctrl+I', 'Meta+Shift+i', wrapHighlighted, 'Format: Highlight'],
['Ctrl+.', 'Meta+.', wrapLifted, 'Format: Superscript'], ['Ctrl+.', 'Meta+.', wrapLifted, 'Format: Superscript'],
['Ctrl+Comma', 'Meta+Comma', wrapLowered, 'Format: Subscript'], ['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+X', 'Meta+Shift+x', wrapStrikethrough, 'Format: Strikethrough'],
['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'], ['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'],
]; ];
editorShortcuts.fakeItem('Editor'); editorShortcuts.group('Editor', function () {
editorShortcuts.groupStart();
for (let shortcut of shortcuts) { for (let shortcut of shortcuts) {
if (isMac) { if (isMac) {
editorShortcuts.add(shortcut[1], ...shortcut.slice(2)) this.add(shortcut[1], ...shortcut.slice(2))
} else { } else {
editorShortcuts.add(shortcut[0], ...shortcut.slice(2)) this.add(shortcut[0], ...shortcut.slice(2))
} }
} }
editorShortcuts.groupEnd(); });
editorShortcuts.groupStart(); editorShortcuts.group(function () {
bindElement(isMac ? 'Meta+Enter' : 'Ctrl+Enter', $('.edit-form__save'), 'Save changes'); this.bindElement(isMac ? 'Meta+Enter' : 'Ctrl+Enter', $('.edit-form__save'), 'Save changes');
editorShortcuts.groupEnd(); });
// Help shortcut
editorShortcuts.add(isMac ? 'Meta+/' : 'Ctrl+/', openShortcutsReference);
} }
// * Meta shortcuts
globalShortcuts.add('?', openShortcutsReference);
}); });
})(); })();

View File

@ -83,7 +83,7 @@
<br/><br/> <br/><br/>
<input type="submit" name="action" value="Save" class="edit-form__save"/> <input type="submit" name="action" value="Save" class="edit-form__save"/>
<input type="submit" name="action" value="Preview" class="edit-form__preview"> <input type="submit" name="action" value="Preview" class="edit-form__preview">
<a href="/page/{%s hyphaName %}" class="edit-form__cancel">Cancel</a> <a href="/hypha/{%s hyphaName %}" class="edit-form__cancel">Cancel</a>
</form> </form>
</main> </main>
{%s= Toolbar(user.FromRequest(rq)) %} {%s= Toolbar(user.FromRequest(rq)) %}
@ -106,7 +106,7 @@
<br/><br/> <br/><br/>
<input type="submit" name="action" value="Save" class="edit-form__save"/> <input type="submit" name="action" value="Save" class="edit-form__save"/>
<input type="submit" name="action" value="Preview" class="edit-form__preview"> <input type="submit" name="action" value="Preview" class="edit-form__preview">
<a href="/page/{%s hyphaName %}" class="edit-form__cancel">Cancel</a> <a href="/hypha/{%s hyphaName %}" class="edit-form__cancel">Cancel</a>
</form> </form>
<p class="warning">Note that the hypha is not saved yet. You can preview the changes ↓</p> <p class="warning">Note that the hypha is not saved yet. You can preview the changes ↓</p>
<article class="edit__preview">{%s= renderedPage %}</article> <article class="edit__preview">{%s= renderedPage %}</article>

View File

@ -210,8 +210,8 @@ func StreamEditHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, text
<br/><br/> <br/><br/>
<input type="submit" name="action" value="Save" class="edit-form__save"/> <input type="submit" name="action" value="Save" class="edit-form__save"/>
<input type="submit" name="action" value="Preview" class="edit-form__preview"> <input type="submit" name="action" value="Preview" class="edit-form__preview">
<a href="/page/`) <a href="/hypha/`)
//line views/mutators.qtpl:86 //line views/mutators.qtpl:83
qw422016.E().S(hyphaName) qw422016.E().S(hyphaName)
//line views/mutators.qtpl:86 //line views/mutators.qtpl:86
qw422016.N().S(`" class="edit-form__cancel">Cancel</a> qw422016.N().S(`" class="edit-form__cancel">Cancel</a>
@ -300,8 +300,8 @@ func StreamPreviewHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, t
<br/><br/> <br/><br/>
<input type="submit" name="action" value="Save" class="edit-form__save"/> <input type="submit" name="action" value="Save" class="edit-form__save"/>
<input type="submit" name="action" value="Preview" class="edit-form__preview"> <input type="submit" name="action" value="Preview" class="edit-form__preview">
<a href="/page/`) <a href="/hypha/`)
//line views/mutators.qtpl:109 //line views/mutators.qtpl:103
qw422016.E().S(hyphaName) qw422016.E().S(hyphaName)
//line views/mutators.qtpl:109 //line views/mutators.qtpl:109
qw422016.N().S(`" class="edit-form__cancel">Cancel</a> qw422016.N().S(`" class="edit-form__cancel">Cancel</a>

View File

@ -11,7 +11,7 @@ type navEntry struct {
title string title string
} }
var navEntries = []navEntry{ var navEntries = []navEntry{
{"page", "Hypha"}, {"hypha", "Hypha"},
{"edit", "Edit"}, {"edit", "Edit"},
{"attachment", "Attachment"}, {"attachment", "Attachment"},
{"history", "History"}, {"history", "History"},

View File

@ -41,7 +41,7 @@ type navEntry struct {
} }
var navEntries = []navEntry{ var navEntries = []navEntry{
{"page", "Hypha"}, {"hypha", "Hypha"},
{"edit", "Edit"}, {"edit", "Edit"},
{"attachment", "Attachment"}, {"attachment", "Attachment"},
{"history", "History"}, {"history", "History"},

View File

@ -80,7 +80,7 @@ If `contents` == "", a helpful message is shown instead.
relatives, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name) relatives, subhyphae, prevHyphaName, nextHyphaName := tree.Tree(h.Name)
u := user.FromRequest(rq) u := user.FromRequest(rq)
%} %}
{%= NavHTML(rq, h.Name, "page") %} {%= NavHTML(rq, h.Name, "hypha") %}
<div class="layout"> <div class="layout">
<main class="main-width"> <main class="main-width">
<article> <article>

View File

@ -241,7 +241,7 @@ func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hyph
qw422016.N().S(` qw422016.N().S(`
`) `)
//line views/readers.qtpl:83 //line views/readers.qtpl:83
StreamNavHTML(qw422016, rq, h.Name, "page") StreamNavHTML(qw422016, rq, h.Name, "hypha")
//line views/readers.qtpl:83 //line views/readers.qtpl:83
qw422016.N().S(` qw422016.N().S(`
<div class="layout"> <div class="layout">

View File

@ -28,6 +28,17 @@
</nav> </nav>
</header> </header>
{%s= body %} {%s= body %}
<template id="dialog-template">
<div class="dialog-backdrop"></div>
<div class="dialog" tabindex="0">
<div class="dialog__header">
<h1 class="dialog__title"></h1>
<button class="dialog__close-button" aria-label="Close this dialog"></button>
</div>
<div class="dialog__content"></div>
</div>
</template>
{%= omnipresentScripts() %} {%= omnipresentScripts() %}
</body> </body>
</html> </html>
@ -57,19 +68,19 @@ for u := range user.YieldUsers() {
<section> <section>
<h2>Admins</h2> <h2>Admins</h2>
<ol>{% for _, name := range admins %} <ol>{% for _, name := range admins %}
<li><a href="/page/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li> <li><a href="/hypha/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li>
{% endfor %}</ol> {% endfor %}</ol>
</section> </section>
<section> <section>
<h2>Moderators</h2> <h2>Moderators</h2>
<ol>{% for _, name := range moderators %} <ol>{% for _, name := range moderators %}
<li><a href="/page/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li> <li><a href="/hypha/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li>
{% endfor %}</ol> {% endfor %}</ol>
</section> </section>
<section> <section>
<h2>Editors</h2> <h2>Editors</h2>
<ol>{% for _, name := range editors %} <ol>{% for _, name := range editors %}
<li><a href="/page/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li> <li><a href="/hypha/{%s cfg.UserHypha %}/{%s name %}">{%s name %}</a></li>
{% endfor %}</ol> {% endfor %}</ol>
</section> </section>
</main> </main>
@ -108,7 +119,7 @@ for u := range user.YieldUsers() {
<li><b>Administrators:</b> {%- for i, username := range user.ListUsersWithGroup("admin") -%} <li><b>Administrators:</b> {%- for i, username := range user.ListUsersWithGroup("admin") -%}
{%- if i > 0 -%}<span aria-hidden="true">, </span> {%- if i > 0 -%}<span aria-hidden="true">, </span>
{%- endif -%} {%- endif -%}
<a href="/page/{%s cfg.UserHypha %}/{%s username %}">{%s username %}</a>{%- endfor -%}</li> <a href="/hypha/{%s cfg.UserHypha %}/{%s username %}">{%s username %}</a>{%- endfor -%}</li>
{%- else -%} {%- else -%}
<li>This wiki does not use authorization</li> <li>This wiki does not use authorization</li>
{%- endif -%} {%- endif -%}

View File

@ -93,52 +93,63 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User,
qw422016.N().S(body) qw422016.N().S(body)
//line views/stuff.qtpl:30 //line views/stuff.qtpl:30
qw422016.N().S(` qw422016.N().S(`
<template id="dialog-template">
<div class="dialog-backdrop"></div>
<div class="dialog" tabindex="0">
<div class="dialog__header">
<h1 class="dialog__title"></h1>
<button class="dialog__close-button" aria-label="Close this dialog"></button>
</div>
<div class="dialog__content"></div>
</div>
</template>
`) `)
//line views/stuff.qtpl:31 //line views/stuff.qtpl:42
streamomnipresentScripts(qw422016) streamomnipresentScripts(qw422016)
//line views/stuff.qtpl:31 //line views/stuff.qtpl:42
qw422016.N().S(` qw422016.N().S(`
</body> </body>
</html> </html>
`) `)
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
} }
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
func WriteBaseHTML(qq422016 qtio422016.Writer, title, body string, u *user.User, headElements ...string) { func WriteBaseHTML(qq422016 qtio422016.Writer, title, body string, u *user.User, headElements ...string) {
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
StreamBaseHTML(qw422016, title, body, u, headElements...) StreamBaseHTML(qw422016, title, body, u, headElements...)
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
} }
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
func BaseHTML(title, body string, u *user.User, headElements ...string) string { func BaseHTML(title, body string, u *user.User, headElements ...string) string {
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
WriteBaseHTML(qb422016, title, body, u, headElements...) WriteBaseHTML(qb422016, title, body, u, headElements...)
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
return qs422016 return qs422016
//line views/stuff.qtpl:34 //line views/stuff.qtpl:45
} }
//line views/stuff.qtpl:36 //line views/stuff.qtpl:47
func StreamUserListHTML(qw422016 *qt422016.Writer) { func StreamUserListHTML(qw422016 *qt422016.Writer) {
//line views/stuff.qtpl:36 //line views/stuff.qtpl:47
qw422016.N().S(` qw422016.N().S(`
<div class="layout"> <div class="layout">
<main class="main-width user-list"> <main class="main-width user-list">
<h1>List of users</h1> <h1>List of users</h1>
`) `)
//line views/stuff.qtpl:41 //line views/stuff.qtpl:52
var ( var (
admins = make([]string, 0) admins = make([]string, 0)
moderators = make([]string, 0) moderators = make([]string, 0)
@ -155,303 +166,303 @@ func StreamUserListHTML(qw422016 *qt422016.Writer) {
} }
} }
//line views/stuff.qtpl:56 //line views/stuff.qtpl:67
qw422016.N().S(` qw422016.N().S(`
<section> <section>
<h2>Admins</h2> <h2>Admins</h2>
<ol>`) <ol>`)
//line views/stuff.qtpl:59 //line views/stuff.qtpl:70
for _, name := range admins { for _, name := range admins {
//line views/stuff.qtpl:59 //line views/stuff.qtpl:70
qw422016.N().S(` qw422016.N().S(`
<li><a href="/page/`) <li><a href="/hypha/`)
//line views/stuff.qtpl:60 //line views/stuff.qtpl:71
qw422016.E().S(cfg.UserHypha) qw422016.E().S(cfg.UserHypha)
//line views/stuff.qtpl:60 //line views/stuff.qtpl:71
qw422016.N().S(`/`) qw422016.N().S(`/`)
//line views/stuff.qtpl:60 //line views/stuff.qtpl:71
qw422016.E().S(name) qw422016.E().S(name)
//line views/stuff.qtpl:60 //line views/stuff.qtpl:71
qw422016.N().S(`">`) qw422016.N().S(`">`)
//line views/stuff.qtpl:60 //line views/stuff.qtpl:71
qw422016.E().S(name) qw422016.E().S(name)
//line views/stuff.qtpl:60 //line views/stuff.qtpl:71
qw422016.N().S(`</a></li> qw422016.N().S(`</a></li>
`) `)
//line views/stuff.qtpl:61 //line views/stuff.qtpl:72
} }
//line views/stuff.qtpl:61 //line views/stuff.qtpl:72
qw422016.N().S(`</ol> qw422016.N().S(`</ol>
</section> </section>
<section> <section>
<h2>Moderators</h2> <h2>Moderators</h2>
<ol>`) <ol>`)
//line views/stuff.qtpl:65 //line views/stuff.qtpl:76
for _, name := range moderators { for _, name := range moderators {
//line views/stuff.qtpl:65 //line views/stuff.qtpl:76
qw422016.N().S(` qw422016.N().S(`
<li><a href="/page/`) <li><a href="/hypha/`)
//line views/stuff.qtpl:66 //line views/stuff.qtpl:77
qw422016.E().S(cfg.UserHypha) qw422016.E().S(cfg.UserHypha)
//line views/stuff.qtpl:66 //line views/stuff.qtpl:77
qw422016.N().S(`/`) qw422016.N().S(`/`)
//line views/stuff.qtpl:66 //line views/stuff.qtpl:77
qw422016.E().S(name) qw422016.E().S(name)
//line views/stuff.qtpl:66 //line views/stuff.qtpl:77
qw422016.N().S(`">`) qw422016.N().S(`">`)
//line views/stuff.qtpl:66 //line views/stuff.qtpl:77
qw422016.E().S(name) qw422016.E().S(name)
//line views/stuff.qtpl:66 //line views/stuff.qtpl:77
qw422016.N().S(`</a></li> qw422016.N().S(`</a></li>
`) `)
//line views/stuff.qtpl:67 //line views/stuff.qtpl:78
} }
//line views/stuff.qtpl:67 //line views/stuff.qtpl:78
qw422016.N().S(`</ol> qw422016.N().S(`</ol>
</section> </section>
<section> <section>
<h2>Editors</h2> <h2>Editors</h2>
<ol>`) <ol>`)
//line views/stuff.qtpl:71 //line views/stuff.qtpl:82
for _, name := range editors { for _, name := range editors {
//line views/stuff.qtpl:71 //line views/stuff.qtpl:82
qw422016.N().S(` qw422016.N().S(`
<li><a href="/page/`) <li><a href="/hypha/`)
//line views/stuff.qtpl:72 //line views/stuff.qtpl:83
qw422016.E().S(cfg.UserHypha) qw422016.E().S(cfg.UserHypha)
//line views/stuff.qtpl:72 //line views/stuff.qtpl:83
qw422016.N().S(`/`) qw422016.N().S(`/`)
//line views/stuff.qtpl:72 //line views/stuff.qtpl:83
qw422016.E().S(name) qw422016.E().S(name)
//line views/stuff.qtpl:72 //line views/stuff.qtpl:83
qw422016.N().S(`">`) qw422016.N().S(`">`)
//line views/stuff.qtpl:72 //line views/stuff.qtpl:83
qw422016.E().S(name) qw422016.E().S(name)
//line views/stuff.qtpl:72 //line views/stuff.qtpl:83
qw422016.N().S(`</a></li> qw422016.N().S(`</a></li>
`) `)
//line views/stuff.qtpl:73 //line views/stuff.qtpl:84
} }
//line views/stuff.qtpl:73 //line views/stuff.qtpl:84
qw422016.N().S(`</ol> qw422016.N().S(`</ol>
</section> </section>
</main> </main>
</div> </div>
`) `)
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
} }
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
func WriteUserListHTML(qq422016 qtio422016.Writer) { func WriteUserListHTML(qq422016 qtio422016.Writer) {
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
StreamUserListHTML(qw422016) StreamUserListHTML(qw422016)
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
} }
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
func UserListHTML() string { func UserListHTML() string {
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
WriteUserListHTML(qb422016) WriteUserListHTML(qb422016)
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
return qs422016 return qs422016
//line views/stuff.qtpl:77 //line views/stuff.qtpl:88
} }
//line views/stuff.qtpl:79 //line views/stuff.qtpl:90
func StreamHyphaListHTML(qw422016 *qt422016.Writer) { func StreamHyphaListHTML(qw422016 *qt422016.Writer) {
//line views/stuff.qtpl:79 //line views/stuff.qtpl:90
qw422016.N().S(` qw422016.N().S(`
<div class="layout"> <div class="layout">
<main class="main-width"> <main class="main-width">
<h1>List of hyphae</h1> <h1>List of hyphae</h1>
<p>This wiki has `) <p>This wiki has `)
//line views/stuff.qtpl:83 //line views/stuff.qtpl:94
qw422016.N().D(hyphae.Count()) qw422016.N().D(hyphae.Count())
//line views/stuff.qtpl:83 //line views/stuff.qtpl:94
qw422016.N().S(` hyphae.</p> qw422016.N().S(` hyphae.</p>
<ul class="hypha-list"> <ul class="hypha-list">
`) `)
//line views/stuff.qtpl:85 //line views/stuff.qtpl:96
for h := range hyphae.YieldExistingHyphae() { for h := range hyphae.YieldExistingHyphae() {
//line views/stuff.qtpl:85 //line views/stuff.qtpl:96
qw422016.N().S(` qw422016.N().S(`
<li class="hypha-list__entry"> <li class="hypha-list__entry">
<a class="hypha-list__link" href="/hypha/`) <a class="hypha-list__link" href="/hypha/`)
//line views/stuff.qtpl:87 //line views/stuff.qtpl:98
qw422016.E().S(h.Name) qw422016.E().S(h.Name)
//line views/stuff.qtpl:87 //line views/stuff.qtpl:98
qw422016.N().S(`">`) qw422016.N().S(`">`)
//line views/stuff.qtpl:87 //line views/stuff.qtpl:98
qw422016.E().S(util.BeautifulName(h.Name)) qw422016.E().S(util.BeautifulName(h.Name))
//line views/stuff.qtpl:87 //line views/stuff.qtpl:98
qw422016.N().S(`</a> qw422016.N().S(`</a>
`) `)
//line views/stuff.qtpl:88 //line views/stuff.qtpl:99
if h.BinaryPath != "" { if h.BinaryPath != "" {
//line views/stuff.qtpl:88 //line views/stuff.qtpl:99
qw422016.N().S(` qw422016.N().S(`
<span class="hypha-list__amnt-type">`) <span class="hypha-list__amnt-type">`)
//line views/stuff.qtpl:89 //line views/stuff.qtpl:100
qw422016.E().S(filepath.Ext(h.BinaryPath)[1:]) qw422016.E().S(filepath.Ext(h.BinaryPath)[1:])
//line views/stuff.qtpl:89 //line views/stuff.qtpl:100
qw422016.N().S(`</span> qw422016.N().S(`</span>
`) `)
//line views/stuff.qtpl:90 //line views/stuff.qtpl:101
} }
//line views/stuff.qtpl:90 //line views/stuff.qtpl:101
qw422016.N().S(` qw422016.N().S(`
</li> </li>
`) `)
//line views/stuff.qtpl:92 //line views/stuff.qtpl:103
} }
//line views/stuff.qtpl:92 //line views/stuff.qtpl:103
qw422016.N().S(` qw422016.N().S(`
</ul> </ul>
</main> </main>
</div> </div>
`) `)
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
} }
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
func WriteHyphaListHTML(qq422016 qtio422016.Writer) { func WriteHyphaListHTML(qq422016 qtio422016.Writer) {
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
StreamHyphaListHTML(qw422016) StreamHyphaListHTML(qw422016)
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
} }
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
func HyphaListHTML() string { func HyphaListHTML() string {
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
WriteHyphaListHTML(qb422016) WriteHyphaListHTML(qb422016)
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
return qs422016 return qs422016
//line views/stuff.qtpl:96 //line views/stuff.qtpl:107
} }
//line views/stuff.qtpl:98 //line views/stuff.qtpl:109
func StreamAboutHTML(qw422016 *qt422016.Writer) { func StreamAboutHTML(qw422016 *qt422016.Writer) {
//line views/stuff.qtpl:98 //line views/stuff.qtpl:109
qw422016.N().S(` qw422016.N().S(`
<div class="layout"> <div class="layout">
<main class="main-width"> <main class="main-width">
<section> <section>
<h1>About `) <h1>About `)
//line views/stuff.qtpl:102 //line views/stuff.qtpl:113
qw422016.E().S(cfg.WikiName) qw422016.E().S(cfg.WikiName)
//line views/stuff.qtpl:102 //line views/stuff.qtpl:113
qw422016.N().S(`</h1> qw422016.N().S(`</h1>
<ul> <ul>
<li><b><a href="https://mycorrhiza.lesarbr.es">Mycorrhiza Wiki</a> version:</b> 1.2.0 indev</li> <li><b><a href="https://mycorrhiza.lesarbr.es">Mycorrhiza Wiki</a> version:</b> 1.2.0 indev</li>
`) `)
//line views/stuff.qtpl:105 //line views/stuff.qtpl:116
if user.AuthUsed { if user.AuthUsed {
//line views/stuff.qtpl:105 //line views/stuff.qtpl:116
qw422016.N().S(` <li><b>User count:</b> `) qw422016.N().S(` <li><b>User count:</b> `)
//line views/stuff.qtpl:106 //line views/stuff.qtpl:117
qw422016.N().D(user.Count()) qw422016.N().D(user.Count())
//line views/stuff.qtpl:106 //line views/stuff.qtpl:117
qw422016.N().S(`</li> qw422016.N().S(`</li>
<li><b>Home page:</b> <a href="/">`) <li><b>Home page:</b> <a href="/">`)
//line views/stuff.qtpl:107 //line views/stuff.qtpl:118
qw422016.E().S(cfg.HomeHypha) qw422016.E().S(cfg.HomeHypha)
//line views/stuff.qtpl:107 //line views/stuff.qtpl:118
qw422016.N().S(`</a></li> qw422016.N().S(`</a></li>
<li><b>Administrators:</b>`) <li><b>Administrators:</b>`)
//line views/stuff.qtpl:108 //line views/stuff.qtpl:119
for i, username := range user.ListUsersWithGroup("admin") { for i, username := range user.ListUsersWithGroup("admin") {
//line views/stuff.qtpl:109 //line views/stuff.qtpl:120
if i > 0 { if i > 0 {
//line views/stuff.qtpl:109 //line views/stuff.qtpl:120
qw422016.N().S(`<span aria-hidden="true">, </span> qw422016.N().S(`<span aria-hidden="true">, </span>
`) `)
//line views/stuff.qtpl:110 //line views/stuff.qtpl:121
} }
//line views/stuff.qtpl:110 //line views/stuff.qtpl:121
qw422016.N().S(` <a href="/page/`) qw422016.N().S(` <a href="/hypha/`)
//line views/stuff.qtpl:111 //line views/stuff.qtpl:122
qw422016.E().S(cfg.UserHypha) qw422016.E().S(cfg.UserHypha)
//line views/stuff.qtpl:111 //line views/stuff.qtpl:122
qw422016.N().S(`/`) qw422016.N().S(`/`)
//line views/stuff.qtpl:111 //line views/stuff.qtpl:122
qw422016.E().S(username) qw422016.E().S(username)
//line views/stuff.qtpl:111 //line views/stuff.qtpl:122
qw422016.N().S(`">`) qw422016.N().S(`">`)
//line views/stuff.qtpl:111 //line views/stuff.qtpl:122
qw422016.E().S(username) qw422016.E().S(username)
//line views/stuff.qtpl:111 //line views/stuff.qtpl:122
qw422016.N().S(`</a>`) qw422016.N().S(`</a>`)
//line views/stuff.qtpl:111 //line views/stuff.qtpl:122
} }
//line views/stuff.qtpl:111 //line views/stuff.qtpl:122
qw422016.N().S(`</li> qw422016.N().S(`</li>
`) `)
//line views/stuff.qtpl:112 //line views/stuff.qtpl:123
} else { } else {
//line views/stuff.qtpl:112 //line views/stuff.qtpl:123
qw422016.N().S(` <li>This wiki does not use authorization</li> qw422016.N().S(` <li>This wiki does not use authorization</li>
`) `)
//line views/stuff.qtpl:114 //line views/stuff.qtpl:125
} }
//line views/stuff.qtpl:114 //line views/stuff.qtpl:125
qw422016.N().S(` </ul> qw422016.N().S(` </ul>
<p>See <a href="/list">/list</a> for information about hyphae on this wiki.</p> <p>See <a href="/list">/list</a> for information about hyphae on this wiki.</p>
</section> </section>
</main> </main>
</div> </div>
`) `)
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
} }
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
func WriteAboutHTML(qq422016 qtio422016.Writer) { func WriteAboutHTML(qq422016 qtio422016.Writer) {
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
StreamAboutHTML(qw422016) StreamAboutHTML(qw422016)
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
} }
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
func AboutHTML() string { func AboutHTML() string {
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
WriteAboutHTML(qb422016) WriteAboutHTML(qb422016)
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
return qs422016 return qs422016
//line views/stuff.qtpl:120 //line views/stuff.qtpl:131
} }
//line views/stuff.qtpl:122 //line views/stuff.qtpl:133
func StreamAdminPanelHTML(qw422016 *qt422016.Writer) { func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
//line views/stuff.qtpl:122 //line views/stuff.qtpl:133
qw422016.N().S(` qw422016.N().S(`
<div class="layout"> <div class="layout">
<main class="main-width"> <main class="main-width">
@ -488,80 +499,80 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
</main> </main>
</div> </div>
`) `)
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
} }
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
func WriteAdminPanelHTML(qq422016 qtio422016.Writer) { func WriteAdminPanelHTML(qq422016 qtio422016.Writer) {
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
StreamAdminPanelHTML(qw422016) StreamAdminPanelHTML(qw422016)
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
} }
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
func AdminPanelHTML() string { func AdminPanelHTML() string {
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
WriteAdminPanelHTML(qb422016) WriteAdminPanelHTML(qb422016)
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
return qs422016 return qs422016
//line views/stuff.qtpl:157 //line views/stuff.qtpl:168
} }
//line views/stuff.qtpl:159 //line views/stuff.qtpl:170
func streamomnipresentScripts(qw422016 *qt422016.Writer) { func streamomnipresentScripts(qw422016 *qt422016.Writer) {
//line views/stuff.qtpl:159 //line views/stuff.qtpl:170
qw422016.N().S(` qw422016.N().S(`
`) `)
//line views/stuff.qtpl:160 //line views/stuff.qtpl:171
for _, scriptPath := range cfg.OmnipresentScripts { for _, scriptPath := range cfg.OmnipresentScripts {
//line views/stuff.qtpl:160 //line views/stuff.qtpl:171
qw422016.N().S(` qw422016.N().S(`
<script src="`) <script src="`)
//line views/stuff.qtpl:161 //line views/stuff.qtpl:172
qw422016.E().S(scriptPath) qw422016.E().S(scriptPath)
//line views/stuff.qtpl:161 //line views/stuff.qtpl:172
qw422016.N().S(`"></script> qw422016.N().S(`"></script>
`) `)
//line views/stuff.qtpl:162 //line views/stuff.qtpl:173
} }
//line views/stuff.qtpl:162 //line views/stuff.qtpl:173
qw422016.N().S(` qw422016.N().S(`
`) `)
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
} }
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
func writeomnipresentScripts(qq422016 qtio422016.Writer) { func writeomnipresentScripts(qq422016 qtio422016.Writer) {
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
qw422016 := qt422016.AcquireWriter(qq422016) qw422016 := qt422016.AcquireWriter(qq422016)
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
streamomnipresentScripts(qw422016) streamomnipresentScripts(qw422016)
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
qt422016.ReleaseWriter(qw422016) qt422016.ReleaseWriter(qw422016)
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
} }
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
func omnipresentScripts() string { func omnipresentScripts() string {
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
qb422016 := qt422016.AcquireByteBuffer() qb422016 := qt422016.AcquireByteBuffer()
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
writeomnipresentScripts(qb422016) writeomnipresentScripts(qb422016)
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
qs422016 := string(qb422016.B) qs422016 := string(qb422016.B)
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
qt422016.ReleaseByteBuffer(qb422016) qt422016.ReleaseByteBuffer(qb422016)
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
return qs422016 return qs422016
//line views/stuff.qtpl:163 //line views/stuff.qtpl:174
} }

View File

@ -30,7 +30,7 @@ func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) {
views.BaseHTML( views.BaseHTML(
title, title,
fmt.Sprintf( fmt.Sprintf(
`<main class="main-width"><p>%s. <a href="/page/%s">Go back to the hypha.<a></p></main>`, `<main class="main-width"><p>%s. <a href="/hypha/%s">Go back to the hypha.<a></p></main>`,
errMsg, errMsg,
name, name,
), ),