diff --git a/js/forum/src/components/CommentPost.js b/js/forum/src/components/CommentPost.js
index 73e873591..aca1e97aa 100644
--- a/js/forum/src/components/CommentPost.js
+++ b/js/forum/src/components/CommentPost.js
@@ -6,6 +6,7 @@ import PostEdited from 'flarum/components/PostEdited';
import EditPostComposer from 'flarum/components/EditPostComposer';
import Composer from 'flarum/components/Composer';
import ItemList from 'flarum/utils/ItemList';
+import formatText from 'flarum/utils/formatText';
import listItems from 'flarum/helpers/listItems';
import Button from 'flarum/components/Button';
@@ -33,18 +34,32 @@ export default class CommentPost extends Post {
// Create an instance of the component that displays the post's author so
// that we can force the post to rerender when the user card is shown.
this.postUser = new PostUser({post: this.props.post});
- this.subtree.check(() => this.postUser.cardVisible);
+ this.subtree.check(
+ () => this.postUser.cardVisible,
+ () => this.props.post.editedContent,
+ () => this.isEditing()
+ );
}
content() {
+ const content = this.isEditing()
+ ? formatText(this.props.post.editedContent)
+ : this.props.post.contentHtml();
+
return [
{listItems(this.headerItems().toArray())}
,
-
{ReplyPlaceholder.component({discussion: this.discussion})}
@@ -517,8 +516,12 @@ class PostStream extends mixin(Component, evented) {
const scrollBottom = scrollTop + $(window).height();
// If the item is already in the viewport, we may not need to scroll.
+ // If we're scrolling to the bottom of an item, then we'll make sure the
+ // bottom will line up with the top of the composer.
if (force || itemTop < scrollTop || itemBottom > scrollBottom) {
- const top = bottom ? itemBottom : ($item.is(':first-child') ? 0 : itemTop);
+ const top = bottom
+ ? itemBottom - $(window).height() + app.composer.computedHeight()
+ : ($item.is(':first-child') ? 0 : itemTop);
if (noAnimation) {
$container.scrollTop(top);
diff --git a/js/forum/src/components/PostUser.js b/js/forum/src/components/PostUser.js
index abc7e2503..0bbaf1420 100644
--- a/js/forum/src/components/PostUser.js
+++ b/js/forum/src/components/PostUser.js
@@ -30,7 +30,7 @@ export default class PostUser extends Component {
if (!user) {
return (
-
{avatar(user)} {username(user)}
+ {avatar(user, {className: 'PostUser-avatar'})} {username(user)}
);
}
diff --git a/js/forum/src/components/ReplyComposer.js b/js/forum/src/components/ReplyComposer.js
index 684fcebdb..b887f70c7 100644
--- a/js/forum/src/components/ReplyComposer.js
+++ b/js/forum/src/components/ReplyComposer.js
@@ -34,6 +34,27 @@ export default class ReplyComposer extends ComposerBody {
return items;
}
+ config(isInitialized, context) {
+ super.config(isInitialized, context);
+
+ if (isInitialized) return;
+
+ // Every 50ms, if the content has changed, then update the post's
+ // editedContent property and redraw. This will cause the preview in the
+ // post's component to update.
+ const updateInterval = setInterval(() => {
+ const discussion = this.props.discussion;
+ const content = this.content();
+
+ if (content === discussion.replyContent) return;
+
+ discussion.replyContent = content;
+ m.redraw();
+ }, 50);
+
+ context.onunload = () => clearInterval(updateInterval);
+ }
+
/**
* Get the data to submit to the server when the reply is saved.
*
diff --git a/js/forum/src/components/ReplyPlaceholder.js b/js/forum/src/components/ReplyPlaceholder.js
index a5b2005bb..1ec54251b 100644
--- a/js/forum/src/components/ReplyPlaceholder.js
+++ b/js/forum/src/components/ReplyPlaceholder.js
@@ -1,6 +1,8 @@
import Component from 'flarum/Component';
import avatar from 'flarum/helpers/avatar';
+import username from 'flarum/helpers/username';
import DiscussionControls from 'flarum/utils/DiscussionControls';
+import formatText from 'flarum/utils/formatText';
/**
* The `ReplyPlaceholder` component displays a placeholder for a reply, which,
@@ -12,6 +14,24 @@ import DiscussionControls from 'flarum/utils/DiscussionControls';
*/
export default class ReplyPlaceholder extends Component {
view() {
+ if (app.composingReplyTo(this.props.discussion)) {
+ return (
+
+
+
+ {m.trust(formatText(this.props.discussion.replyContent))}
+
+
+ );
+ }
+
function triggerClick(e) {
$(this).trigger('click');
e.preventDefault();
diff --git a/js/forum/src/utils/formatText.js b/js/forum/src/utils/formatText.js
new file mode 100644
index 000000000..1c21de3f4
--- /dev/null
+++ b/js/forum/src/utils/formatText.js
@@ -0,0 +1,7 @@
+export default function formatText(text) {
+ const elm = document.createElement('div');
+
+ s9e.TextFormatter.preview(text || '', elm);
+
+ return elm.innerHTML;
+}
diff --git a/less/forum/Post.less b/less/forum/Post.less
index 9ac808baf..9e85ac4c9 100644
--- a/less/forum/Post.less
+++ b/less/forum/Post.less
@@ -9,7 +9,7 @@
&.editing {
top: 5px;
- opacity: 0.2;
+ opacity: 0.5;
}
}
.Post-controls {
diff --git a/src/Assets/AssetManager.php b/src/Assets/AssetManager.php
index 78ae0f8e1..3c9e45da3 100644
--- a/src/Assets/AssetManager.php
+++ b/src/Assets/AssetManager.php
@@ -29,7 +29,7 @@ class AssetManager
break;
default:
- throw new DomainException('Unsupported asset type: '.$ext);
+ throw new DomainException('Unsupported asset type: ' . $ext);
}
}
@@ -38,14 +38,14 @@ class AssetManager
array_walk($files, [$this, 'addFile']);
}
- public function addLess($string)
+ public function addLess(callable $callback)
{
- $this->less->addString($string);
+ $this->less->addString($callback);
}
- public function addJs($strings)
+ public function addJs(callable $callback)
{
- $this->js->addString($string);
+ $this->js->addString($callback);
}
public function getCssFile()
diff --git a/src/Assets/Compiler.php b/src/Assets/Compiler.php
index 11db8d5e4..e26357a1a 100644
--- a/src/Assets/Compiler.php
+++ b/src/Assets/Compiler.php
@@ -4,7 +4,7 @@ interface Compiler
{
public function addFile($file);
- public function addString($string);
+ public function addString(callable $callback);
public function getFile();
}
diff --git a/src/Assets/LessCompiler.php b/src/Assets/LessCompiler.php
index 4483e1c0d..4338c8535 100644
--- a/src/Assets/LessCompiler.php
+++ b/src/Assets/LessCompiler.php
@@ -17,8 +17,8 @@ class LessCompiler extends RevisionCompiler
$parser->parseFile($file);
}
- foreach ($this->strings as $string) {
- $parser->parse($string);
+ foreach ($this->strings as $callback) {
+ $parser->parse($callback());
}
return $parser->getCss();
diff --git a/src/Assets/RevisionCompiler.php b/src/Assets/RevisionCompiler.php
index 6d01b6e69..148f2901c 100644
--- a/src/Assets/RevisionCompiler.php
+++ b/src/Assets/RevisionCompiler.php
@@ -19,9 +19,9 @@ class RevisionCompiler implements Compiler
$this->files[] = $file;
}
- public function addString($string)
+ public function addString(callable $callback)
{
- $this->strings[] = $string;
+ $this->strings[] = $callback;
}
public function getFile()
@@ -63,8 +63,8 @@ class RevisionCompiler implements Compiler
$output .= $this->format(file_get_contents($file));
}
- foreach ($this->strings as $string) {
- $output .= $this->format($string);
+ foreach ($this->strings as $callback) {
+ $output .= $this->format($callback());
}
return $output;
diff --git a/src/Forum/Actions/ClientAction.php b/src/Forum/Actions/ClientAction.php
index b63afaf02..b4390fce0 100644
--- a/src/Forum/Actions/ClientAction.php
+++ b/src/Forum/Actions/ClientAction.php
@@ -131,4 +131,15 @@ abstract class ClientAction extends BaseClientAction
'core.write_a_post',
'core.write_a_reply'
];
+
+ protected function getAssets()
+ {
+ $assets = parent::getAssets();
+
+ $assets->addJs(function () {
+ return app('flarum.formatter')->getJS();
+ });
+
+ return $assets;
+ }
}
diff --git a/src/Support/ClientAction.php b/src/Support/ClientAction.php
index 64025e29f..be3d09c90 100644
--- a/src/Support/ClientAction.php
+++ b/src/Support/ClientAction.php
@@ -160,11 +160,17 @@ abstract class ClientAction extends HtmlAction
*/
protected function addCustomizations(AssetManager $assets)
{
- foreach ($this->getLessVariables() as $name => $value) {
- $assets->addLess("@$name: $value;");
- }
+ $assets->addLess(function () {
+ $less = '';
- $assets->addLess($this->settings->get('custom_less'));
+ foreach ($this->getLessVariables() as $name => $value) {
+ $less .= "@$name: $value;";
+ }
+
+ $less .= $this->settings->get('custom_less');
+
+ return $less;
+ });
}
/**