mirror of
https://github.com/osmarks/mycorrhiza.git
synced 2024-10-30 11:46:16 +00:00
Merge branch 'master' into master
This commit is contained in:
commit
679588abd5
@ -141,7 +141,7 @@ func (rev *Revision) asHistoryEntry(hyphaName string) (html string) {
|
||||
author := ""
|
||||
if rev.Username != "anon" {
|
||||
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(`
|
||||
<li class="history__entry">
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 `<kbd>${Shortcut.symbolifyKey(key, isMac)}</kbd>`;
|
||||
}).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] = `<kbd>${keys[i]}</kbd>`;
|
||||
}
|
||||
|
||||
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(' <span class="kbd-or">or</span> ');
|
||||
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);
|
||||
});
|
||||
})();
|
||||
|
@ -83,7 +83,7 @@
|
||||
<br/><br/>
|
||||
<input type="submit" name="action" value="Save" class="edit-form__save"/>
|
||||
<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>
|
||||
</main>
|
||||
{%s= Toolbar(user.FromRequest(rq)) %}
|
||||
@ -106,7 +106,7 @@
|
||||
<br/><br/>
|
||||
<input type="submit" name="action" value="Save" class="edit-form__save"/>
|
||||
<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>
|
||||
<p class="warning">Note that the hypha is not saved yet. You can preview the changes ↓</p>
|
||||
<article class="edit__preview">{%s= renderedPage %}</article>
|
||||
|
@ -210,8 +210,8 @@ func StreamEditHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, text
|
||||
<br/><br/>
|
||||
<input type="submit" name="action" value="Save" class="edit-form__save"/>
|
||||
<input type="submit" name="action" value="Preview" class="edit-form__preview">
|
||||
<a href="/page/`)
|
||||
//line views/mutators.qtpl:86
|
||||
<a href="/hypha/`)
|
||||
//line views/mutators.qtpl:83
|
||||
qw422016.E().S(hyphaName)
|
||||
//line views/mutators.qtpl:86
|
||||
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/>
|
||||
<input type="submit" name="action" value="Save" class="edit-form__save"/>
|
||||
<input type="submit" name="action" value="Preview" class="edit-form__preview">
|
||||
<a href="/page/`)
|
||||
//line views/mutators.qtpl:109
|
||||
<a href="/hypha/`)
|
||||
//line views/mutators.qtpl:103
|
||||
qw422016.E().S(hyphaName)
|
||||
//line views/mutators.qtpl:109
|
||||
qw422016.N().S(`" class="edit-form__cancel">Cancel</a>
|
||||
|
@ -11,7 +11,7 @@ type navEntry struct {
|
||||
title string
|
||||
}
|
||||
var navEntries = []navEntry{
|
||||
{"page", "Hypha"},
|
||||
{"hypha", "Hypha"},
|
||||
{"edit", "Edit"},
|
||||
{"attachment", "Attachment"},
|
||||
{"history", "History"},
|
||||
|
@ -41,7 +41,7 @@ type navEntry struct {
|
||||
}
|
||||
|
||||
var navEntries = []navEntry{
|
||||
{"page", "Hypha"},
|
||||
{"hypha", "Hypha"},
|
||||
{"edit", "Edit"},
|
||||
{"attachment", "Attachment"},
|
||||
{"history", "History"},
|
||||
|
@ -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") %}
|
||||
<div class="layout">
|
||||
<main class="main-width">
|
||||
<article>
|
||||
|
@ -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(`
|
||||
<div class="layout">
|
||||
|
@ -28,6 +28,17 @@
|
||||
</nav>
|
||||
</header>
|
||||
{%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() %}
|
||||
</body>
|
||||
</html>
|
||||
@ -57,19 +68,19 @@ for u := range user.YieldUsers() {
|
||||
<section>
|
||||
<h2>Admins</h2>
|
||||
<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>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Moderators</h2>
|
||||
<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>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Editors</h2>
|
||||
<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>
|
||||
</section>
|
||||
</main>
|
||||
@ -108,7 +119,7 @@ for u := range user.YieldUsers() {
|
||||
<li><b>Administrators:</b> {%- for i, username := range user.ListUsersWithGroup("admin") -%}
|
||||
{%- if i > 0 -%}<span aria-hidden="true">, </span>
|
||||
{%- 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 -%}
|
||||
<li>This wiki does not use authorization</li>
|
||||
{%- endif -%}
|
||||
|
@ -93,52 +93,63 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User,
|
||||
qw422016.N().S(body)
|
||||
//line views/stuff.qtpl:30
|
||||
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)
|
||||
//line views/stuff.qtpl:31
|
||||
//line views/stuff.qtpl:42
|
||||
qw422016.N().S(`
|
||||
</body>
|
||||
</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) {
|
||||
//line views/stuff.qtpl:34
|
||||
//line views/stuff.qtpl:45
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/stuff.qtpl:34
|
||||
//line views/stuff.qtpl:45
|
||||
StreamBaseHTML(qw422016, title, body, u, headElements...)
|
||||
//line views/stuff.qtpl:34
|
||||
//line views/stuff.qtpl:45
|
||||
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 {
|
||||
//line views/stuff.qtpl:34
|
||||
//line views/stuff.qtpl:45
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/stuff.qtpl:34
|
||||
//line views/stuff.qtpl:45
|
||||
WriteBaseHTML(qb422016, title, body, u, headElements...)
|
||||
//line views/stuff.qtpl:34
|
||||
//line views/stuff.qtpl:45
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/stuff.qtpl:34
|
||||
//line views/stuff.qtpl:45
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/stuff.qtpl:34
|
||||
//line views/stuff.qtpl:45
|
||||
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) {
|
||||
//line views/stuff.qtpl:36
|
||||
//line views/stuff.qtpl:47
|
||||
qw422016.N().S(`
|
||||
<div class="layout">
|
||||
<main class="main-width user-list">
|
||||
<h1>List of users</h1>
|
||||
`)
|
||||
//line views/stuff.qtpl:41
|
||||
//line views/stuff.qtpl:52
|
||||
var (
|
||||
admins = 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(`
|
||||
<section>
|
||||
<h2>Admins</h2>
|
||||
<ol>`)
|
||||
//line views/stuff.qtpl:59
|
||||
//line views/stuff.qtpl:70
|
||||
for _, name := range admins {
|
||||
//line views/stuff.qtpl:59
|
||||
//line views/stuff.qtpl:70
|
||||
qw422016.N().S(`
|
||||
<li><a href="/page/`)
|
||||
//line views/stuff.qtpl:60
|
||||
<li><a href="/hypha/`)
|
||||
//line views/stuff.qtpl:71
|
||||
qw422016.E().S(cfg.UserHypha)
|
||||
//line views/stuff.qtpl:60
|
||||
//line views/stuff.qtpl:71
|
||||
qw422016.N().S(`/`)
|
||||
//line views/stuff.qtpl:60
|
||||
//line views/stuff.qtpl:71
|
||||
qw422016.E().S(name)
|
||||
//line views/stuff.qtpl:60
|
||||
//line views/stuff.qtpl:71
|
||||
qw422016.N().S(`">`)
|
||||
//line views/stuff.qtpl:60
|
||||
//line views/stuff.qtpl:71
|
||||
qw422016.E().S(name)
|
||||
//line views/stuff.qtpl:60
|
||||
//line views/stuff.qtpl:71
|
||||
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>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Moderators</h2>
|
||||
<ol>`)
|
||||
//line views/stuff.qtpl:65
|
||||
//line views/stuff.qtpl:76
|
||||
for _, name := range moderators {
|
||||
//line views/stuff.qtpl:65
|
||||
//line views/stuff.qtpl:76
|
||||
qw422016.N().S(`
|
||||
<li><a href="/page/`)
|
||||
//line views/stuff.qtpl:66
|
||||
<li><a href="/hypha/`)
|
||||
//line views/stuff.qtpl:77
|
||||
qw422016.E().S(cfg.UserHypha)
|
||||
//line views/stuff.qtpl:66
|
||||
//line views/stuff.qtpl:77
|
||||
qw422016.N().S(`/`)
|
||||
//line views/stuff.qtpl:66
|
||||
//line views/stuff.qtpl:77
|
||||
qw422016.E().S(name)
|
||||
//line views/stuff.qtpl:66
|
||||
//line views/stuff.qtpl:77
|
||||
qw422016.N().S(`">`)
|
||||
//line views/stuff.qtpl:66
|
||||
//line views/stuff.qtpl:77
|
||||
qw422016.E().S(name)
|
||||
//line views/stuff.qtpl:66
|
||||
//line views/stuff.qtpl:77
|
||||
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>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Editors</h2>
|
||||
<ol>`)
|
||||
//line views/stuff.qtpl:71
|
||||
//line views/stuff.qtpl:82
|
||||
for _, name := range editors {
|
||||
//line views/stuff.qtpl:71
|
||||
//line views/stuff.qtpl:82
|
||||
qw422016.N().S(`
|
||||
<li><a href="/page/`)
|
||||
//line views/stuff.qtpl:72
|
||||
<li><a href="/hypha/`)
|
||||
//line views/stuff.qtpl:83
|
||||
qw422016.E().S(cfg.UserHypha)
|
||||
//line views/stuff.qtpl:72
|
||||
//line views/stuff.qtpl:83
|
||||
qw422016.N().S(`/`)
|
||||
//line views/stuff.qtpl:72
|
||||
//line views/stuff.qtpl:83
|
||||
qw422016.E().S(name)
|
||||
//line views/stuff.qtpl:72
|
||||
//line views/stuff.qtpl:83
|
||||
qw422016.N().S(`">`)
|
||||
//line views/stuff.qtpl:72
|
||||
//line views/stuff.qtpl:83
|
||||
qw422016.E().S(name)
|
||||
//line views/stuff.qtpl:72
|
||||
//line views/stuff.qtpl:83
|
||||
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>
|
||||
</section>
|
||||
</main>
|
||||
</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) {
|
||||
//line views/stuff.qtpl:77
|
||||
//line views/stuff.qtpl:88
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/stuff.qtpl:77
|
||||
//line views/stuff.qtpl:88
|
||||
StreamUserListHTML(qw422016)
|
||||
//line views/stuff.qtpl:77
|
||||
//line views/stuff.qtpl:88
|
||||
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 {
|
||||
//line views/stuff.qtpl:77
|
||||
//line views/stuff.qtpl:88
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/stuff.qtpl:77
|
||||
//line views/stuff.qtpl:88
|
||||
WriteUserListHTML(qb422016)
|
||||
//line views/stuff.qtpl:77
|
||||
//line views/stuff.qtpl:88
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/stuff.qtpl:77
|
||||
//line views/stuff.qtpl:88
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/stuff.qtpl:77
|
||||
//line views/stuff.qtpl:88
|
||||
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) {
|
||||
//line views/stuff.qtpl:79
|
||||
//line views/stuff.qtpl:90
|
||||
qw422016.N().S(`
|
||||
<div class="layout">
|
||||
<main class="main-width">
|
||||
<h1>List of hyphae</h1>
|
||||
<p>This wiki has `)
|
||||
//line views/stuff.qtpl:83
|
||||
//line views/stuff.qtpl:94
|
||||
qw422016.N().D(hyphae.Count())
|
||||
//line views/stuff.qtpl:83
|
||||
//line views/stuff.qtpl:94
|
||||
qw422016.N().S(` hyphae.</p>
|
||||
<ul class="hypha-list">
|
||||
`)
|
||||
//line views/stuff.qtpl:85
|
||||
//line views/stuff.qtpl:96
|
||||
for h := range hyphae.YieldExistingHyphae() {
|
||||
//line views/stuff.qtpl:85
|
||||
//line views/stuff.qtpl:96
|
||||
qw422016.N().S(`
|
||||
<li class="hypha-list__entry">
|
||||
<a class="hypha-list__link" href="/hypha/`)
|
||||
//line views/stuff.qtpl:87
|
||||
//line views/stuff.qtpl:98
|
||||
qw422016.E().S(h.Name)
|
||||
//line views/stuff.qtpl:87
|
||||
//line views/stuff.qtpl:98
|
||||
qw422016.N().S(`">`)
|
||||
//line views/stuff.qtpl:87
|
||||
//line views/stuff.qtpl:98
|
||||
qw422016.E().S(util.BeautifulName(h.Name))
|
||||
//line views/stuff.qtpl:87
|
||||
//line views/stuff.qtpl:98
|
||||
qw422016.N().S(`</a>
|
||||
`)
|
||||
//line views/stuff.qtpl:88
|
||||
//line views/stuff.qtpl:99
|
||||
if h.BinaryPath != "" {
|
||||
//line views/stuff.qtpl:88
|
||||
//line views/stuff.qtpl:99
|
||||
qw422016.N().S(`
|
||||
<span class="hypha-list__amnt-type">`)
|
||||
//line views/stuff.qtpl:89
|
||||
//line views/stuff.qtpl:100
|
||||
qw422016.E().S(filepath.Ext(h.BinaryPath)[1:])
|
||||
//line views/stuff.qtpl:89
|
||||
//line views/stuff.qtpl:100
|
||||
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(`
|
||||
</li>
|
||||
`)
|
||||
//line views/stuff.qtpl:92
|
||||
//line views/stuff.qtpl:103
|
||||
}
|
||||
//line views/stuff.qtpl:92
|
||||
//line views/stuff.qtpl:103
|
||||
qw422016.N().S(`
|
||||
</ul>
|
||||
</main>
|
||||
</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) {
|
||||
//line views/stuff.qtpl:96
|
||||
//line views/stuff.qtpl:107
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/stuff.qtpl:96
|
||||
//line views/stuff.qtpl:107
|
||||
StreamHyphaListHTML(qw422016)
|
||||
//line views/stuff.qtpl:96
|
||||
//line views/stuff.qtpl:107
|
||||
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 {
|
||||
//line views/stuff.qtpl:96
|
||||
//line views/stuff.qtpl:107
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/stuff.qtpl:96
|
||||
//line views/stuff.qtpl:107
|
||||
WriteHyphaListHTML(qb422016)
|
||||
//line views/stuff.qtpl:96
|
||||
//line views/stuff.qtpl:107
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/stuff.qtpl:96
|
||||
//line views/stuff.qtpl:107
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/stuff.qtpl:96
|
||||
//line views/stuff.qtpl:107
|
||||
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) {
|
||||
//line views/stuff.qtpl:98
|
||||
//line views/stuff.qtpl:109
|
||||
qw422016.N().S(`
|
||||
<div class="layout">
|
||||
<main class="main-width">
|
||||
<section>
|
||||
<h1>About `)
|
||||
//line views/stuff.qtpl:102
|
||||
//line views/stuff.qtpl:113
|
||||
qw422016.E().S(cfg.WikiName)
|
||||
//line views/stuff.qtpl:102
|
||||
//line views/stuff.qtpl:113
|
||||
qw422016.N().S(`</h1>
|
||||
<ul>
|
||||
<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 {
|
||||
//line views/stuff.qtpl:105
|
||||
//line views/stuff.qtpl:116
|
||||
qw422016.N().S(` <li><b>User count:</b> `)
|
||||
//line views/stuff.qtpl:106
|
||||
//line views/stuff.qtpl:117
|
||||
qw422016.N().D(user.Count())
|
||||
//line views/stuff.qtpl:106
|
||||
//line views/stuff.qtpl:117
|
||||
qw422016.N().S(`</li>
|
||||
<li><b>Home page:</b> <a href="/">`)
|
||||
//line views/stuff.qtpl:107
|
||||
//line views/stuff.qtpl:118
|
||||
qw422016.E().S(cfg.HomeHypha)
|
||||
//line views/stuff.qtpl:107
|
||||
//line views/stuff.qtpl:118
|
||||
qw422016.N().S(`</a></li>
|
||||
<li><b>Administrators:</b>`)
|
||||
//line views/stuff.qtpl:108
|
||||
//line views/stuff.qtpl:119
|
||||
for i, username := range user.ListUsersWithGroup("admin") {
|
||||
//line views/stuff.qtpl:109
|
||||
//line views/stuff.qtpl:120
|
||||
if i > 0 {
|
||||
//line views/stuff.qtpl:109
|
||||
//line views/stuff.qtpl:120
|
||||
qw422016.N().S(`<span aria-hidden="true">, </span>
|
||||
`)
|
||||
//line views/stuff.qtpl:110
|
||||
//line views/stuff.qtpl:121
|
||||
}
|
||||
//line views/stuff.qtpl:110
|
||||
qw422016.N().S(` <a href="/page/`)
|
||||
//line views/stuff.qtpl:111
|
||||
//line views/stuff.qtpl:121
|
||||
qw422016.N().S(` <a href="/hypha/`)
|
||||
//line views/stuff.qtpl:122
|
||||
qw422016.E().S(cfg.UserHypha)
|
||||
//line views/stuff.qtpl:111
|
||||
//line views/stuff.qtpl:122
|
||||
qw422016.N().S(`/`)
|
||||
//line views/stuff.qtpl:111
|
||||
//line views/stuff.qtpl:122
|
||||
qw422016.E().S(username)
|
||||
//line views/stuff.qtpl:111
|
||||
//line views/stuff.qtpl:122
|
||||
qw422016.N().S(`">`)
|
||||
//line views/stuff.qtpl:111
|
||||
//line views/stuff.qtpl:122
|
||||
qw422016.E().S(username)
|
||||
//line views/stuff.qtpl:111
|
||||
//line views/stuff.qtpl:122
|
||||
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>
|
||||
`)
|
||||
//line views/stuff.qtpl:112
|
||||
//line views/stuff.qtpl:123
|
||||
} else {
|
||||
//line views/stuff.qtpl:112
|
||||
//line views/stuff.qtpl:123
|
||||
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>
|
||||
<p>See <a href="/list">/list</a> for information about hyphae on this wiki.</p>
|
||||
</section>
|
||||
</main>
|
||||
</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) {
|
||||
//line views/stuff.qtpl:120
|
||||
//line views/stuff.qtpl:131
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/stuff.qtpl:120
|
||||
//line views/stuff.qtpl:131
|
||||
StreamAboutHTML(qw422016)
|
||||
//line views/stuff.qtpl:120
|
||||
//line views/stuff.qtpl:131
|
||||
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 {
|
||||
//line views/stuff.qtpl:120
|
||||
//line views/stuff.qtpl:131
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/stuff.qtpl:120
|
||||
//line views/stuff.qtpl:131
|
||||
WriteAboutHTML(qb422016)
|
||||
//line views/stuff.qtpl:120
|
||||
//line views/stuff.qtpl:131
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/stuff.qtpl:120
|
||||
//line views/stuff.qtpl:131
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/stuff.qtpl:120
|
||||
//line views/stuff.qtpl:131
|
||||
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) {
|
||||
//line views/stuff.qtpl:122
|
||||
//line views/stuff.qtpl:133
|
||||
qw422016.N().S(`
|
||||
<div class="layout">
|
||||
<main class="main-width">
|
||||
@ -488,80 +499,80 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
|
||||
</main>
|
||||
</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) {
|
||||
//line views/stuff.qtpl:157
|
||||
//line views/stuff.qtpl:168
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/stuff.qtpl:157
|
||||
//line views/stuff.qtpl:168
|
||||
StreamAdminPanelHTML(qw422016)
|
||||
//line views/stuff.qtpl:157
|
||||
//line views/stuff.qtpl:168
|
||||
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 {
|
||||
//line views/stuff.qtpl:157
|
||||
//line views/stuff.qtpl:168
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/stuff.qtpl:157
|
||||
//line views/stuff.qtpl:168
|
||||
WriteAdminPanelHTML(qb422016)
|
||||
//line views/stuff.qtpl:157
|
||||
//line views/stuff.qtpl:168
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/stuff.qtpl:157
|
||||
//line views/stuff.qtpl:168
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/stuff.qtpl:157
|
||||
//line views/stuff.qtpl:168
|
||||
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) {
|
||||
//line views/stuff.qtpl:159
|
||||
//line views/stuff.qtpl:170
|
||||
qw422016.N().S(`
|
||||
`)
|
||||
//line views/stuff.qtpl:160
|
||||
//line views/stuff.qtpl:171
|
||||
for _, scriptPath := range cfg.OmnipresentScripts {
|
||||
//line views/stuff.qtpl:160
|
||||
//line views/stuff.qtpl:171
|
||||
qw422016.N().S(`
|
||||
<script src="`)
|
||||
//line views/stuff.qtpl:161
|
||||
//line views/stuff.qtpl:172
|
||||
qw422016.E().S(scriptPath)
|
||||
//line views/stuff.qtpl:161
|
||||
//line views/stuff.qtpl:172
|
||||
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(`
|
||||
`)
|
||||
//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) {
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
qw422016 := qt422016.AcquireWriter(qq422016)
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
streamomnipresentScripts(qw422016)
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
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 {
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
qb422016 := qt422016.AcquireByteBuffer()
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
writeomnipresentScripts(qb422016)
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
qs422016 := string(qb422016.B)
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
qt422016.ReleaseByteBuffer(qb422016)
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
return qs422016
|
||||
//line views/stuff.qtpl:163
|
||||
//line views/stuff.qtpl:174
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ func httpErr(w http.ResponseWriter, status int, name, title, errMsg string) {
|
||||
views.BaseHTML(
|
||||
title,
|
||||
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,
|
||||
name,
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user