mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-23 20:18:00 +01:00
Merge pull request #137 from philomena-dev/markdown-frontend
Markdown-based text editor
This commit is contained in:
commit
77b2fb93bd
35 changed files with 424 additions and 482 deletions
|
@ -215,7 +215,7 @@ hr {
|
|||
}
|
||||
}
|
||||
|
||||
//textile
|
||||
// Text Editor
|
||||
blockquote {
|
||||
margin: 1em 2em;
|
||||
border: 1px dotted $foreground_color;
|
||||
|
@ -298,7 +298,7 @@ blockquote blockquote blockquote blockquote blockquote blockquote {
|
|||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.textile-syntax-reference {
|
||||
.editor-syntax-reference {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
|
|
|
@ -222,3 +222,7 @@ a.block__header--single-item, .block__header a {
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.block__content--top-border {
|
||||
border-top: $border;
|
||||
}
|
||||
|
|
|
@ -74,6 +74,10 @@ form p {
|
|||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.input--resize-vertical {
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
margin: 0.2em 0 0 0.4em;
|
||||
padding: 0;
|
||||
|
|
250
assets/js/markdowntoolbar.js
Normal file
250
assets/js/markdowntoolbar.js
Normal file
|
@ -0,0 +1,250 @@
|
|||
/**
|
||||
* Markdown toolbar
|
||||
*/
|
||||
|
||||
import { $, $$ } from './utils/dom';
|
||||
|
||||
const markdownSyntax = {
|
||||
bold: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '**', shortcutKey: 'b' }
|
||||
},
|
||||
italics: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '*', shortcutKey: 'i' }
|
||||
},
|
||||
under: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '__', shortcutKey: 'u' }
|
||||
},
|
||||
spoiler: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '||', shortcutKey: 's' }
|
||||
},
|
||||
code: {
|
||||
action: wrapSelectionOrLines,
|
||||
options: {
|
||||
prefix: '`',
|
||||
suffix: '`',
|
||||
prefixMultiline: '```\n',
|
||||
suffixMultiline: '\n```',
|
||||
singleWrap: true,
|
||||
shortcutKey: 'e'
|
||||
}
|
||||
},
|
||||
strike: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '~~' }
|
||||
},
|
||||
superscript: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '^' }
|
||||
},
|
||||
subscript: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '%' }
|
||||
},
|
||||
quote: {
|
||||
action: wrapLines,
|
||||
options: { prefix: '> ' }
|
||||
},
|
||||
link: {
|
||||
action: insertLink,
|
||||
options: { shortcutKey: 'l' }
|
||||
},
|
||||
image: {
|
||||
action: insertLink,
|
||||
options: { image: true, shortcutKey: 'k' }
|
||||
},
|
||||
escape: {
|
||||
action: escapeSelection,
|
||||
options: { escapeChar: '\\' }
|
||||
}
|
||||
};
|
||||
|
||||
function getSelections(textarea, linesOnly = false) {
|
||||
let { selectionStart, selectionEnd } = textarea,
|
||||
selection = textarea.value.substring(selectionStart, selectionEnd),
|
||||
leadingSpace = '',
|
||||
trailingSpace = '',
|
||||
caret;
|
||||
|
||||
const processLinesOnly = linesOnly instanceof RegExp ? linesOnly.test(selection) : linesOnly;
|
||||
if (processLinesOnly) {
|
||||
const explorer = /\n/g;
|
||||
let startNewlineIndex = 0,
|
||||
endNewlineIndex = textarea.value.length;
|
||||
while (explorer.exec(textarea.value)) {
|
||||
const { lastIndex } = explorer;
|
||||
if (lastIndex <= selectionStart) {
|
||||
startNewlineIndex = lastIndex;
|
||||
}
|
||||
else if (lastIndex > selectionEnd) {
|
||||
endNewlineIndex = lastIndex - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
selectionStart = startNewlineIndex;
|
||||
const startRemovedValue = textarea.value.substring(selectionStart);
|
||||
const startsWithBlankString = startRemovedValue.match(/^[\s\n]+/);
|
||||
if (startsWithBlankString) {
|
||||
// Offset the selection start to the first non-blank line's first non-blank character, since
|
||||
// Some browsers treat selection up to the start of the line as including the end of the
|
||||
// previous line
|
||||
selectionStart += startsWithBlankString[0].length;
|
||||
}
|
||||
selectionEnd = endNewlineIndex;
|
||||
selection = textarea.value.substring(selectionStart, selectionEnd);
|
||||
}
|
||||
else {
|
||||
// Deselect trailing space and line break
|
||||
for (caret = selection.length - 1; caret > 0; caret--) {
|
||||
if (selection[caret] !== ' ' && selection[caret] !== '\n') break;
|
||||
trailingSpace = selection[caret] + trailingSpace;
|
||||
}
|
||||
selection = selection.substring(0, caret + 1);
|
||||
|
||||
// Deselect leading space and line break
|
||||
for (caret = 0; caret < selection.length; caret++) {
|
||||
if (selection[caret] !== ' ' && selection[caret] !== '\n') break;
|
||||
leadingSpace += selection[caret];
|
||||
}
|
||||
selection = selection.substring(caret);
|
||||
}
|
||||
|
||||
return {
|
||||
processLinesOnly,
|
||||
selectedText: selection,
|
||||
beforeSelection: textarea.value.substring(0, selectionStart) + leadingSpace,
|
||||
afterSelection: trailingSpace + textarea.value.substring(selectionEnd)
|
||||
};
|
||||
}
|
||||
|
||||
function transformSelection(textarea, transformer, eachLine) {
|
||||
const { selectedText, beforeSelection, afterSelection, processLinesOnly } = getSelections(textarea, eachLine),
|
||||
// For long comments, record scrollbar position to restore it later
|
||||
{ scrollTop } = textarea;
|
||||
|
||||
const { newText, caretOffset } = transformer(selectedText, processLinesOnly);
|
||||
|
||||
textarea.value = beforeSelection + newText + afterSelection;
|
||||
|
||||
const newSelectionStart = caretOffset >= 1
|
||||
? beforeSelection.length + caretOffset
|
||||
: textarea.value.length - afterSelection.length - caretOffset;
|
||||
|
||||
textarea.selectionStart = newSelectionStart;
|
||||
textarea.selectionEnd = newSelectionStart;
|
||||
textarea.scrollTop = scrollTop;
|
||||
// Needed for automatic textarea resizing
|
||||
textarea.dispatchEvent(new Event('change'));
|
||||
}
|
||||
|
||||
function insertLink(textarea, options) {
|
||||
let hyperlink = window.prompt(options.image ? 'Image link:' : 'Link:');
|
||||
if (!hyperlink || hyperlink === '') return;
|
||||
|
||||
// Change on-site link to use relative url
|
||||
if (!options.image && hyperlink.startsWith(window.location.origin)) {
|
||||
hyperlink = hyperlink.substring(window.location.origin.length);
|
||||
}
|
||||
|
||||
const prefix = options.image ? '![' : '[',
|
||||
suffix = `](${hyperlink})`;
|
||||
|
||||
wrapSelection(textarea, { prefix, suffix });
|
||||
}
|
||||
|
||||
function wrapSelection(textarea, options) {
|
||||
transformSelection(textarea, selectedText => {
|
||||
const { text = selectedText, prefix = '', suffix = options.prefix } = options,
|
||||
emptyText = text === '';
|
||||
let newText = text;
|
||||
|
||||
if (!emptyText) {
|
||||
newText = text.replace(/(\n{2,})/g, match => {
|
||||
return suffix + match + prefix;
|
||||
});
|
||||
}
|
||||
|
||||
newText = prefix + newText + suffix
|
||||
|
||||
return {
|
||||
newText,
|
||||
caretOffset: emptyText ? prefix.length : newText.length
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function wrapLines(textarea, options, eachLine = true) {
|
||||
transformSelection(textarea, (selectedText, processLinesOnly) => {
|
||||
const { text = selectedText, singleWrap = false } = options,
|
||||
prefix = (processLinesOnly && options.prefixMultiline) || options.prefix || '',
|
||||
suffix = (processLinesOnly && options.suffixMultiline) || options.suffix || '',
|
||||
emptyText = text === '';
|
||||
let newText = singleWrap
|
||||
? prefix + text.trim() + suffix
|
||||
: text.split(/\n/g).map(line => prefix + line.trim() + suffix).join('\n');
|
||||
|
||||
return { newText, caretOffset: emptyText ? prefix.length : newText.length };
|
||||
}, eachLine);
|
||||
}
|
||||
|
||||
function wrapSelectionOrLines(textarea, options) {
|
||||
wrapLines(textarea, options, /\n/);
|
||||
}
|
||||
|
||||
function escapeSelection(textarea, options) {
|
||||
transformSelection(textarea, selectedText => {
|
||||
const { text = selectedText } = options,
|
||||
emptyText = text === '';
|
||||
|
||||
if (emptyText) return;
|
||||
|
||||
const newText = text.replace(/([*_[\]()^`%\\~<>#|])/g, '\\$1');
|
||||
|
||||
return {
|
||||
newText,
|
||||
caretOffset: newText.length
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function clickHandler(event) {
|
||||
const button = event.target.closest('.communication__toolbar__button');
|
||||
if (!button) return;
|
||||
const toolbar = button.closest('.communication__toolbar'),
|
||||
// There may be multiple toolbars present on the page,
|
||||
// in the case of image pages with description edit active
|
||||
// we target the textarea that shares the same parent as the toolbar
|
||||
textarea = $('.js-toolbar-input', toolbar.parentNode),
|
||||
id = button.dataset.syntaxId;
|
||||
|
||||
markdownSyntax[id].action(textarea, markdownSyntax[id].options);
|
||||
textarea.focus();
|
||||
}
|
||||
|
||||
function shortcutHandler(event) {
|
||||
if (!event.ctrlKey || (window.navigator.platform === 'MacIntel' && !event.metaKey) || event.shiftKey || event.altKey) return;
|
||||
const textarea = event.target,
|
||||
key = event.key.toLowerCase();
|
||||
|
||||
for (const id in markdownSyntax) {
|
||||
if (key === markdownSyntax[id].options.shortcutKey) {
|
||||
markdownSyntax[id].action(textarea, markdownSyntax[id].options);
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setupToolbar() {
|
||||
$$('.communication__toolbar').forEach(toolbar => {
|
||||
toolbar.addEventListener('click', clickHandler);
|
||||
});
|
||||
$$('.js-toolbar-input').forEach(textarea => {
|
||||
textarea.addEventListener('keydown', shortcutHandler);
|
||||
});
|
||||
}
|
||||
|
||||
export { setupToolbar };
|
|
@ -1,9 +1,10 @@
|
|||
/**
|
||||
* Textile previews (posts, comments, messages)
|
||||
* Markdown previews (posts, comments, messages)
|
||||
*/
|
||||
|
||||
import { fetchJson } from './utils/requests';
|
||||
import { filterNode } from './imagesclientside';
|
||||
import { hideEl, showEl } from './utils/dom.js';
|
||||
|
||||
function handleError(response) {
|
||||
const errorMessage = '<div>Preview failed to load!</div>';
|
||||
|
@ -35,43 +36,84 @@ function commentReply(user, url, textarea, quote) {
|
|||
textarea.focus();
|
||||
}
|
||||
|
||||
function getPreview(body, anonymous, previewTab, isImage = false) {
|
||||
let path = '/posts/preview';
|
||||
function getPreview(body, anonymous, previewLoading, previewIdle, previewContent) {
|
||||
const path = '/posts/preview';
|
||||
|
||||
if (typeof body !== 'string') return;
|
||||
|
||||
showEl(previewLoading);
|
||||
hideEl(previewIdle);
|
||||
|
||||
fetchJson('POST', path, { body, anonymous })
|
||||
.then(handleError)
|
||||
.then(data => {
|
||||
previewTab.innerHTML = data;
|
||||
filterNode(previewTab);
|
||||
previewContent.innerHTML = data;
|
||||
filterNode(previewContent);
|
||||
showEl(previewIdle);
|
||||
hideEl(previewLoading);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the event target <textarea> to match the size of its contained text, between set
|
||||
* minimum and maximum height values. Former comes from CSS, latter is hard coded below.
|
||||
* @template {{ target: HTMLTextAreaElement }} E
|
||||
* @param {E} e
|
||||
*/
|
||||
function resizeTextarea(e) {
|
||||
// Reset inline height for fresh calculations
|
||||
e.target.style.height = '';
|
||||
const { borderTopWidth, borderBottomWidth, height } = window.getComputedStyle(e.target);
|
||||
// Add scrollHeight and borders (because border-box) to get the target size that avoids scrollbars
|
||||
const contentHeight = e.target.scrollHeight + parseFloat(borderTopWidth) + parseFloat(borderBottomWidth);
|
||||
// Get the original default height provided by page styles
|
||||
const regularHeight = parseFloat(height);
|
||||
// Limit textarea's size to between the original height and 1000px
|
||||
const newHeight = Math.max(regularHeight, Math.min(1000, contentHeight));
|
||||
e.target.style.height = `${newHeight}px`;
|
||||
}
|
||||
|
||||
function setupPreviews() {
|
||||
let textarea = document.querySelector('.js-preview-input');
|
||||
let imageDesc = false;
|
||||
|
||||
if (!textarea) {
|
||||
textarea = document.querySelector('.js-preview-description');
|
||||
imageDesc = true;
|
||||
}
|
||||
|
||||
const previewButton = document.querySelector('a[data-click-tab="preview"]');
|
||||
const previewTab = document.querySelector('.block__tab[data-tab="preview"]');
|
||||
const previewAnon = document.querySelector('.preview-anonymous') || false;
|
||||
const previewLoading = document.querySelector('.js-preview-loading');
|
||||
const previewIdle = document.querySelector('.js-preview-idle');
|
||||
const previewContent = document.querySelector('.js-preview-content');
|
||||
const previewAnon = document.querySelector('.js-preview-anonymous') || false;
|
||||
|
||||
if (!textarea || !previewButton) {
|
||||
if (!textarea || !previewContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
previewButton.addEventListener('click', () => {
|
||||
if (previewTab.previewedText === textarea.value) return;
|
||||
previewTab.previewedText = textarea.value;
|
||||
const getCacheKey = () => {
|
||||
return (previewAnon && previewAnon.checked ? 'anon;' : '') + textarea.value;
|
||||
}
|
||||
|
||||
getPreview(textarea.value, Boolean(previewAnon.checked), previewTab, imageDesc);
|
||||
});
|
||||
const previewedTextAttribute = 'data-previewed-text';
|
||||
const updatePreview = () => {
|
||||
const cachedValue = getCacheKey()
|
||||
if (previewContent.getAttribute(previewedTextAttribute) === cachedValue) return;
|
||||
previewContent.setAttribute(previewedTextAttribute, cachedValue);
|
||||
|
||||
getPreview(textarea.value, previewAnon && previewAnon.checked, previewLoading, previewIdle, previewContent);
|
||||
};
|
||||
|
||||
previewButton.addEventListener('click', updatePreview);
|
||||
textarea.addEventListener('change', resizeTextarea);
|
||||
textarea.addEventListener('keyup', resizeTextarea);
|
||||
|
||||
// Fire handler for automatic resizing if textarea contains text on page load (e.g. editing)
|
||||
if (textarea.value) textarea.dispatchEvent(new Event('change'));
|
||||
|
||||
previewAnon && previewAnon.addEventListener('click', () => {
|
||||
getPreview(textarea.value, Boolean(previewAnon.checked), previewTab, imageDesc);
|
||||
if (previewContent.classList.contains('hidden')) return;
|
||||
|
||||
updatePreview();
|
||||
});
|
||||
|
||||
document.addEventListener('click', event => {
|
||||
|
@ -83,4 +125,4 @@ function setupPreviews() {
|
|||
});
|
||||
}
|
||||
|
||||
export { setupPreviews };
|
||||
export { setupPreviews };
|
||||
|
|
|
@ -1,172 +0,0 @@
|
|||
/**
|
||||
* Textile toolbar
|
||||
*
|
||||
*/
|
||||
|
||||
import { $, $$ } from './utils/dom';
|
||||
|
||||
const textileSyntax = {
|
||||
bold: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '*', suffix: '*', shortcutKey: 'b', type: 'inline' }
|
||||
},
|
||||
italics: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '_', suffix: '_', shortcutKey: 'i', type: 'inline' }
|
||||
},
|
||||
under: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '+', suffix: '+', shortcutKey: 'u', type: 'inline' }
|
||||
},
|
||||
spoiler: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '[spoiler]', suffix: '[/spoiler]', shortcutKey: 's' }
|
||||
},
|
||||
code: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '@', suffix: '@', shortcutKey: 'e', type: 'inline' }
|
||||
},
|
||||
strike: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '-', suffix: '-', type: 'inline' }
|
||||
},
|
||||
superscript: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '^', suffix: '^', type: 'inline' }
|
||||
},
|
||||
subscript: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '~', suffix: '~', type: 'inline' }
|
||||
},
|
||||
quote: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '[bq]', suffix: '[/bq]' }
|
||||
},
|
||||
link: {
|
||||
action: insertLink,
|
||||
options: { prefix: '"', suffix: '":', shortcutKey: 'l' }
|
||||
},
|
||||
image: {
|
||||
action: insertImage,
|
||||
options: { prefix: '!', suffix: '!', shortcutKey: 'k' }
|
||||
},
|
||||
noParse: {
|
||||
action: wrapSelection,
|
||||
options: { prefix: '[==', suffix: '==]' }
|
||||
},
|
||||
};
|
||||
|
||||
function getSelections(textarea) {
|
||||
let selection = textarea.value.substring(textarea.selectionStart, textarea.selectionEnd),
|
||||
leadingSpace = '',
|
||||
trailingSpace = '',
|
||||
caret;
|
||||
|
||||
// Deselect trailing space and line break
|
||||
for (caret = selection.length - 1; caret > 0; caret--) {
|
||||
if (selection[caret] !== ' ' && selection[caret] !== '\n') break;
|
||||
trailingSpace = selection[caret] + trailingSpace;
|
||||
}
|
||||
selection = selection.substring(0, caret + 1);
|
||||
|
||||
// Deselect leading space and line break
|
||||
for (caret = 0; caret < selection.length; caret++) {
|
||||
if (selection[caret] !== ' ' && selection[caret] !== '\n') break;
|
||||
leadingSpace += selection[caret];
|
||||
}
|
||||
selection = selection.substring(caret);
|
||||
|
||||
return {
|
||||
selectedText: selection,
|
||||
beforeSelection: textarea.value.substring(0, textarea.selectionStart) + leadingSpace,
|
||||
afterSelection: trailingSpace + textarea.value.substring(textarea.selectionEnd),
|
||||
};
|
||||
}
|
||||
|
||||
function wrapSelection(textarea, options) {
|
||||
const { selectedText, beforeSelection, afterSelection } = getSelections(textarea),
|
||||
{ text = selectedText, prefix = '', suffix = '', type } = options,
|
||||
// For long comments, record scrollbar position to restore it later
|
||||
scrollTop = textarea.scrollTop,
|
||||
emptyText = text === '';
|
||||
|
||||
const newText = text;
|
||||
|
||||
if (type === 'inline' && newText.includes('\n')) {
|
||||
textarea.value = `${beforeSelection}[${prefix}${newText}${suffix}]${afterSelection}`;
|
||||
}
|
||||
else {
|
||||
textarea.value = `${beforeSelection}${prefix}${newText}${suffix}${afterSelection}`;
|
||||
}
|
||||
|
||||
// If no text were highlighted, place the caret inside
|
||||
// the formatted section, otherwise place it at the end
|
||||
if (emptyText) {
|
||||
textarea.selectionEnd = textarea.value.length - afterSelection.length - suffix.length;
|
||||
}
|
||||
else {
|
||||
textarea.selectionEnd = textarea.value.length - afterSelection.length;
|
||||
}
|
||||
textarea.selectionStart = textarea.selectionEnd;
|
||||
textarea.scrollTop = scrollTop;
|
||||
}
|
||||
|
||||
function insertLink(textarea, options) {
|
||||
let hyperlink = window.prompt('Link:');
|
||||
if (!hyperlink || hyperlink === '') return;
|
||||
|
||||
// Change on-site link to use relative url
|
||||
if (hyperlink.startsWith(window.location.origin)) hyperlink = hyperlink.substring(window.location.origin.length);
|
||||
|
||||
const prefix = options.prefix,
|
||||
suffix = options.suffix + hyperlink;
|
||||
|
||||
wrapSelection(textarea, { prefix, suffix });
|
||||
}
|
||||
|
||||
function insertImage(textarea, options) {
|
||||
const hyperlink = window.prompt('Image link:');
|
||||
const { prefix, suffix } = options;
|
||||
|
||||
if (!hyperlink || hyperlink === '') return;
|
||||
|
||||
wrapSelection(textarea, { text: hyperlink, prefix, suffix });
|
||||
}
|
||||
|
||||
function clickHandler(event) {
|
||||
const button = event.target.closest('.communication__toolbar__button');
|
||||
if (!button) return;
|
||||
const toolbar = button.closest('.communication__toolbar'),
|
||||
// There may be multiple toolbars present on the page,
|
||||
// in the case of image pages with description edit active
|
||||
// we target the textarea that shares the same parent as the toolabr
|
||||
textarea = $('.js-toolbar-input', toolbar.parentNode),
|
||||
id = button.dataset.syntaxId;
|
||||
|
||||
textileSyntax[id].action(textarea, textileSyntax[id].options);
|
||||
textarea.focus();
|
||||
}
|
||||
|
||||
function shortcutHandler(event) {
|
||||
if (!event.ctrlKey || (window.navigator.platform === 'MacIntel' && !event.metaKey) || event.shiftKey || event.altKey) return;
|
||||
const textarea = event.target,
|
||||
key = event.key.toLowerCase();
|
||||
|
||||
for (const id in textileSyntax) {
|
||||
if (key === textileSyntax[id].options.shortcutKey) {
|
||||
textileSyntax[id].action(textarea, textileSyntax[id].options);
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setupToolbar() {
|
||||
$$('.communication__toolbar').forEach(toolbar => {
|
||||
toolbar.addEventListener('click', clickHandler);
|
||||
});
|
||||
$$('.js-toolbar-input').forEach(textarea => {
|
||||
textarea.addEventListener('keydown', shortcutHandler);
|
||||
});
|
||||
}
|
||||
|
||||
export { setupToolbar };
|
|
@ -31,7 +31,7 @@ import { setupTagEvents } from './tagsmisc';
|
|||
import { setupTimestamps } from './timeago';
|
||||
import { setupImageUpload } from './upload';
|
||||
import { setupSearch } from './search';
|
||||
import { setupToolbar } from './textiletoolbar';
|
||||
import { setupToolbar } from './markdowntoolbar.js';
|
||||
import { hideStaffTools } from './staffhider';
|
||||
import { pollOptionCreator } from './poll';
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ article.block.communication id="comment_#{@comment.id}"
|
|||
.flex__fixed.spacing-right
|
||||
.post-image-container
|
||||
= render PhilomenaWeb.ImageView, "_image_container.html", image: @comment.image, size: :thumb_tiny, conn: @conn
|
||||
|
||||
|
||||
.flex__grow.communication__body
|
||||
span.communication__body__sender-name = render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @comment, awards: true, conn: @conn
|
||||
br
|
||||
|
|
|
@ -1,24 +1,7 @@
|
|||
= form_for @changeset, Routes.conversation_message_path(@conn, :create, @conversation), fn f ->
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fa.fa-pencil-alt>
|
||||
| Reply
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
| Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea f, :body, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Your message", required: true
|
||||
= error_tag f, :body
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
| [Loading preview...]
|
||||
.communication-edit__wrap
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, action_icon: "pencil-alt", action_text: "Reply"
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
= submit "Send", class: "button", autocomplete: "off", data: [disable_with: "Sending..."]
|
||||
= submit "Send", class: "button", autocomplete: "off", data: [disable_with: raw("Sending…")]
|
||||
|
|
|
@ -20,25 +20,8 @@ h1 New Conversation
|
|||
= error_tag f, :title
|
||||
|
||||
= inputs_for f, :messages, fn fm ->
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fa.fa-pencil-alt>
|
||||
| Reply
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
| Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
= textarea fm, :body, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Your message", required: true
|
||||
= error_tag fm, :body
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
| [Loading preview...]
|
||||
div
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", changeset: @changeset, conn: @conn, f: fm, action_icon: "pencil-alt", action_text: "Compose"
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
= submit "Send", class: "button", autocomplete: "off", data: [disable_with: "Sending..."]
|
||||
|
|
|
@ -6,29 +6,10 @@
|
|||
p Oops, something went wrong! Please check the errors below.
|
||||
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fas.fa-edit>
|
||||
' Edit
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea f, :body, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Please read the site rules before posting and use [spoiler][/spoiler] for above-rating stuff.", required: true
|
||||
= error_tag f, :body
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
div
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, placeholder: "Please read the site rules before posting and use ||spoilers|| for above-rating stuff."
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
=> submit "Post", class: "button", data: [disable_with: raw("Posting…")]
|
||||
|
||||
= if @conn.assigns.current_user do
|
||||
= checkbox f, :anonymous, value: anonymous_by_default?(@conn)
|
||||
= label f, :anonymous, "Anonymous"
|
||||
= render PhilomenaWeb.MarkdownView, "_anon_checkbox.html", conn: @conn, f: f
|
||||
|
|
|
@ -4,29 +4,12 @@
|
|||
p Oops, something went wrong! Please check the errors below.
|
||||
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fas.fa-edit>
|
||||
' Edit
|
||||
.communication-edit__wrap
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, placeholder: "Please read the site rules before posting and use ||spoilers|| for above-rating stuff."
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea f, :body, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Please read the site rules before posting and use [spoiler][/spoiler] for above-rating stuff.", required: true
|
||||
= error_tag f, :body
|
||||
|
||||
.field
|
||||
= text_input f, :edit_reason, class: "input input--wide", placeholder: "Reason for edit"
|
||||
= error_tag f, :edit_reason
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
.block__content.field
|
||||
= text_input f, :edit_reason, class: "input input--wide", placeholder: "Reason for edit"
|
||||
= error_tag f, :edit_reason
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
=> submit "Edit", class: "button", data: [disable_with: raw("Posting…")]
|
||||
|
|
|
@ -43,4 +43,4 @@ h1
|
|||
' Edited
|
||||
=> pretty_time(version.created_at)
|
||||
' by
|
||||
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: version, conn: @conn
|
||||
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: version, conn: @conn
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
.alert.alert-danger
|
||||
p Oops, something went wrong! Please check the errors below.
|
||||
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
= render PhilomenaWeb.MarkdownView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.MarkdownView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea f, :description, id: "description", class: "input input--wide js-toolbar-input", placeholder: "Describe this image in plain words - this should generally be info about the image that doesn't belong in the tags or source."
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
.field
|
||||
= label f, :source_url, "The page you found this image on"
|
||||
= url_input f, :source_url, class: "input input--wide js-image-input", placeholder: "Source URL"
|
||||
|
||||
|
||||
.field
|
||||
label for="image[tag_input]"
|
||||
' Describe with
|
||||
|
@ -64,24 +64,12 @@
|
|||
|
||||
.field
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
= link "Description", to: "#", class: "selected", data: [click_tab: "write"]
|
||||
= link "Preview", to: "#", data: [click_tab: "preview"]
|
||||
.communication-edit__wrap
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, action_icon: "pencil-alt", action_text: "Description", placeholder: "Describe this image in plain words - this should generally be info about the image that doesn't belong in the tags or source."
|
||||
|
||||
.block__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
= textarea f, :description, class: "input input--wide input--text js-preview-description js-image-input js-toolbar-input", placeholder: "Describe this image in plain words - this should generally be info about the image that doesn't belong in the tags or source."
|
||||
.block__tab.hidden data-tab="preview"
|
||||
| Loading preview...
|
||||
|
||||
= if @conn.assigns.current_user do
|
||||
.field
|
||||
= label f, :anonymous, "Post anonymously"
|
||||
= checkbox f, :anonymous, class: "checkbox", value: anonymous_by_default?(@conn)
|
||||
= render PhilomenaWeb.MarkdownView, "_anon_checkbox.html", conn: @conn, f: f, label: "Post anonymously"
|
||||
|
||||
= render PhilomenaWeb.CaptchaView, "_captcha.html", name: "image", conn: @conn
|
||||
|
||||
.actions
|
||||
= submit "Upload", class: "button", autocomplete: "off", data: [disable_with: "Please wait..."]
|
||||
= submit "Upload", class: "button input--separate-top", autocomplete: "off", data: [disable_with: "Please wait..."]
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
- f = assigns[:f]
|
||||
- label_lext = assigns[:label] || "Anonymous"
|
||||
= if @conn.assigns.current_user do
|
||||
=> checkbox f, :anonymous, value: anonymous_by_default?(@conn), class: "js-preview-anonymous"
|
||||
= label f, :anonymous, label_lext
|
17
lib/philomena_web/templates/markdown/_help.html.slime
Normal file
17
lib/philomena_web/templates/markdown/_help.html.slime
Normal file
|
@ -0,0 +1,17 @@
|
|||
.editor-syntax-reference
|
||||
strong<> Syntax quick reference:
|
||||
|
||||
span
|
||||
strong> **bold**
|
||||
em> *italic*
|
||||
span.spoiler> ||hide text||
|
||||
code> `code`
|
||||
ins> __underline__
|
||||
del> ~~strike~~
|
||||
sup> ^sup^
|
||||
sub %sub%
|
||||
|
||||
p
|
||||
a href="/pages/markdown"
|
||||
i.fa.fa-question-circle>
|
||||
strong Detailed syntax guide
|
24
lib/philomena_web/templates/markdown/_input.html.slime
Normal file
24
lib/philomena_web/templates/markdown/_input.html.slime
Normal file
|
@ -0,0 +1,24 @@
|
|||
- form = assigns[:f]
|
||||
- action_text = assigns[:action_text] || 'Edit'
|
||||
- action_icon = assigns[:action_icon] || 'edit'
|
||||
- field_name = assigns[:name] || :body
|
||||
- field_placeholder = assigns[:placeholder] || "Your message"
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fa> class="fa-#{action_icon}"
|
||||
= action_text
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-cog.fa-fw.fa-spin.js-preview-loading.hidden> title=raw('Loading preview…')
|
||||
i.fa.fa-eye.fa-fw.js-preview-idle>
|
||||
| Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected.js-preview-input-wrapper data-tab="write"
|
||||
= render PhilomenaWeb.MarkdownView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.MarkdownView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea form, field_name, class: "input input--wide input--text input--resize-vertical js-toolbar-input js-preview-input", placeholder: field_placeholder, required: true
|
||||
= error_tag form, field_name
|
||||
|
||||
.block__tab.communication-edit__tab.hidden.js-preview-content data-tab="preview"
|
|
@ -29,6 +29,6 @@
|
|||
i.fa.fa-link
|
||||
button.communication__toolbar__button tabindex="-1" type="button" title="insert image (ctrl+k)" data-syntax-id="image"
|
||||
i.fa.fa-image
|
||||
button.communication__toolbar__button tabindex="-1" type="button" title="Text you want the parser to ignore" data-syntax-id="noParse"
|
||||
button.communication__toolbar__button tabindex="-1" type="button" title="Text you want the parser to ignore" data-syntax-id="escape"
|
||||
span
|
||||
| no parse
|
||||
| escape
|
|
@ -2,9 +2,9 @@
|
|||
.flex__fixed.spacing-right
|
||||
= render PhilomenaWeb.UserAttributionView, "_anon_user_avatar.html", object: @post, conn: @conn
|
||||
|
||||
.flex__grow.communication_body
|
||||
.flex__grow.communication__body
|
||||
span.communication__body__sender-name
|
||||
= render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: @post, conn: @conn, awards: true
|
||||
|
||||
.communication__body__text
|
||||
== @body
|
||||
== @body
|
||||
|
|
|
@ -14,25 +14,8 @@ h1 Updating Profile Description
|
|||
= error_tag f, :personal_title
|
||||
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fas.fa-edit>
|
||||
' About Me
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea f, :description, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Description (up to 10000 characters)"
|
||||
= error_tag f, :description
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
div
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, action_text: "About Me", placeholder: "Description (up to 10000 characters)", name: :description
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
=> submit "Update", class: "button"
|
||||
|
|
|
@ -5,25 +5,8 @@ h1 Updating Moderation Scratchpad
|
|||
.alert.alert-danger
|
||||
p Oops, something went wrong! Please check the errors below.
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fas.fa-edit>
|
||||
' Scratchpad
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea f, :scratchpad, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Scratchpad Contents"
|
||||
= error_tag f, :scratchpad
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
div
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, action_text: "Scratchpad", placeholder: "Scratchpad Contents", name: :scratchpad
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
=> submit "Update", class: "button"
|
||||
|
|
|
@ -45,24 +45,7 @@ p
|
|||
.field
|
||||
= select f, :category, report_categories(), class: "input"
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fas.fa-edit>
|
||||
' Edit
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea f, :reason, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Provide anything else we should know here."
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, placeholder: "Provide anything else we should know here.", name: :reason
|
||||
|
||||
= render PhilomenaWeb.CaptchaView, "_captcha.html", name: "report", conn: @conn
|
||||
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
.textile-syntax-reference
|
||||
strong<> Syntax quick reference:
|
||||
|
||||
span
|
||||
strong>
|
||||
' *bold*
|
||||
em> _italic_
|
||||
span.spoiler>
|
||||
| [spoiler]hide text[/spoiler]
|
||||
code> @code@
|
||||
ins> +underline+
|
||||
del> -strike-
|
||||
sup> ^sup^
|
||||
sub ~sub~
|
||||
|
||||
button< class="button" type="button" data-click-toggle="button:hover + .textile_help, button:focus + .textile_help"
|
||||
' …
|
||||
|
||||
p.hidden.textile_help
|
||||
' [==stuff you don't want textile to parse==]
|
||||
br
|
||||
|
||||
ins> Links:
|
||||
' "On-site link":/some-link, "External link":http://some-link
|
||||
br
|
||||
|
||||
ins> Images:
|
||||
' >>1 — link to image, >>1t — embed image thumbnail (>>1p — large preview, >>1s — small thumbnail)
|
||||
br
|
||||
|
||||
ins> External images:
|
||||
' !http://some-image!, !http://some-clickable-image!:http://some-link
|
||||
br
|
||||
|
||||
strong> Remember to use embeds (>>) for booru images as these let users filter content they don't want to see
|
|
@ -3,43 +3,26 @@
|
|||
.alert.alert-danger
|
||||
p Oops, something went wrong! Please check the errors below.
|
||||
|
||||
h1 Create a Topic
|
||||
|
||||
.field
|
||||
= text_input f, :title, class: "input input--wide", placeholder: "Title"
|
||||
= error_tag f, :title
|
||||
= error_tag f, :slug
|
||||
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fas.fa-pencil-alt>
|
||||
' Create a Topic
|
||||
= inputs_for f, :posts, fn fp ->
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: fp, action_icon: "pencil-alt", action_text: "First Post", placeholder: "Please read the site rules before posting and use ||spoilers|| for NSFW stuff in SFW forums."
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
.field
|
||||
= text_input f, :title, class: "input input--wide", placeholder: "Title"
|
||||
= error_tag f, :title
|
||||
= error_tag f, :slug
|
||||
|
||||
= inputs_for f, :posts, fn fp ->
|
||||
.field
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
= textarea fp, :body, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Please read the site rules before posting and use [spoiler][/spoiler] for NSFW stuff in SFW forums.", required: true
|
||||
= error_tag fp, :body
|
||||
|
||||
= if @conn.assigns.current_user do
|
||||
.field
|
||||
=> checkbox f, :anonymous, value: anonymous_by_default?(@conn)
|
||||
= label f, :anonymous, "Post anonymously"
|
||||
.block__content.communication-edit__wrap
|
||||
= render PhilomenaWeb.MarkdownView, "_anon_checkbox.html", conn: @conn, f: f, label: "Post anonymously"
|
||||
|
||||
= inputs_for f, :poll, fn fp ->
|
||||
#add-poll
|
||||
#add-poll.field
|
||||
input.toggle-box id="add_poll" name="add_poll" type="checkbox"
|
||||
label for="add_poll" Add a poll
|
||||
.toggle-box-container
|
||||
= render PhilomenaWeb.Topic.PollView, "_form.html", Map.put(assigns, :f, fp)
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
= submit "Post", class: "button", data: [disable_with: raw("Posting…")]
|
||||
|
|
|
@ -4,29 +4,10 @@
|
|||
p Oops, something went wrong! Please check the errors below.
|
||||
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fas.fa-edit>
|
||||
' Edit
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
.field
|
||||
= textarea f, :body, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Please read the site rules before posting and use [spoiler][/spoiler] for NSFW stuff in SFW forums.", required: true
|
||||
= error_tag f, :body
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
div
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, placeholder: "Please read the site rules before posting and use ||spoilers|| for NSFW stuff in SFW forums."
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
=> submit "Post", class: "button", data: [disable_with: raw("Posting…")]
|
||||
|
||||
= if @conn.assigns.current_user do
|
||||
= checkbox f, :anonymous, value: anonymous_by_default?(@conn)
|
||||
= label f, :anonymous, "Anonymous"
|
||||
= render PhilomenaWeb.MarkdownView, "_anon_checkbox.html", conn: @conn, f: f
|
||||
|
|
|
@ -4,29 +4,13 @@
|
|||
p Oops, something went wrong! Please check the errors below.
|
||||
|
||||
.block
|
||||
.block__header.block__header--js-tabbed
|
||||
a.selected href="#" data-click-tab="write"
|
||||
i.fas.fa-edit>
|
||||
' Edit
|
||||
|
||||
a href="#" data-click-tab="preview"
|
||||
i.fa.fa-eye>
|
||||
' Preview
|
||||
|
||||
.block__tab.communication-edit__tab.selected data-tab="write"
|
||||
= render PhilomenaWeb.TextileView, "_help.html", conn: @conn
|
||||
= render PhilomenaWeb.TextileView, "_toolbar.html", conn: @conn
|
||||
|
||||
.communication-edit__wrap
|
||||
.field
|
||||
= textarea f, :body, class: "input input--wide input--text js-preview-input js-toolbar-input", placeholder: "Please read the site rules before posting and use [spoiler][/spoiler] for above-rating stuff.", required: true
|
||||
= error_tag f, :body
|
||||
= render PhilomenaWeb.MarkdownView, "_input.html", conn: @conn, f: f, placeholder: "Please read the site rules before posting and use ||spoilers|| for NSFW stuff in SFW forums."
|
||||
|
||||
.field
|
||||
.block__content.field
|
||||
= text_input f, :edit_reason, class: "input input--wide", placeholder: "Reason for edit"
|
||||
= error_tag f, :edit_reason
|
||||
|
||||
.block__tab.communication-edit__tab.hidden data-tab="preview"
|
||||
' [Loading preview...]
|
||||
|
||||
.block__content.communication-edit__actions
|
||||
=> submit "Edit", class: "button", data: [disable_with: raw("Posting…")]
|
||||
|
|
|
@ -42,4 +42,4 @@ h1
|
|||
' Edited
|
||||
=> pretty_time(version.created_at)
|
||||
' by
|
||||
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: version, conn: @conn
|
||||
=> render PhilomenaWeb.UserAttributionView, "_anon_user.html", object: version, conn: @conn
|
||||
|
|
|
@ -108,7 +108,7 @@ h1 = @topic.title
|
|||
- true ->
|
||||
|
||||
= if can?(@conn, :hide, @topic) do
|
||||
.block__content
|
||||
.block__content.block__content--top-border
|
||||
input.toggle-box id="administrator_tools" type="checkbox" checked=false
|
||||
label for="administrator_tools" Manage Topic
|
||||
.toggle-box-container
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
defmodule PhilomenaWeb.Image.CommentView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def anonymous_by_default?(conn) do
|
||||
conn.assigns.current_user.anonymous_by_default
|
||||
end
|
||||
end
|
||||
|
|
|
@ -175,10 +175,6 @@ defmodule PhilomenaWeb.ImageView do
|
|||
|
||||
def scope(conn), do: PhilomenaWeb.ImageScope.scope(conn)
|
||||
|
||||
def anonymous_by_default?(conn) do
|
||||
conn.assigns.current_user.anonymous_by_default
|
||||
end
|
||||
|
||||
def info_row(_conn, []), do: []
|
||||
|
||||
def info_row(conn, [{tag, description, dnp_entries}]) do
|
||||
|
|
7
lib/philomena_web/views/markdown_view.ex
Normal file
7
lib/philomena_web/views/markdown_view.ex
Normal file
|
@ -0,0 +1,7 @@
|
|||
defmodule PhilomenaWeb.MarkdownView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def anonymous_by_default?(conn) do
|
||||
conn.assigns.current_user.anonymous_by_default
|
||||
end
|
||||
end
|
|
@ -1,3 +0,0 @@
|
|||
defmodule PhilomenaWeb.TextileView do
|
||||
use PhilomenaWeb, :view
|
||||
end
|
|
@ -1,7 +1,3 @@
|
|||
defmodule PhilomenaWeb.Topic.PostView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def anonymous_by_default?(conn) do
|
||||
conn.assigns.current_user.anonymous_by_default
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
defmodule PhilomenaWeb.TopicView do
|
||||
use PhilomenaWeb, :view
|
||||
|
||||
def anonymous_by_default?(conn) do
|
||||
conn.assigns.current_user.anonymous_by_default
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue