New component for post excerpts, which will be shown in search results

Perhaps also in user activity stream. They are used in the mentions
extension.

In order to generate the excerpt, each formatter can implement a
“strip” method which basically converts block formatting into inline
formatting.
This commit is contained in:
Toby Zerner 2015-05-14 22:20:17 +09:30
parent 5c6eaefb1f
commit 4a7bd67199
6 changed files with 97 additions and 30 deletions

View File

@ -0,0 +1,22 @@
import Component from 'flarum/component';
import avatar from 'flarum/helpers/avatar';
import username from 'flarum/helpers/username';
import humanTime from 'flarum/helpers/human-time';
export default class PostPreview extends Component {
view() {
var post = this.props.post;
var user = post.user();
return m('a.post-preview', {
href: app.route.post(post),
config: m.route,
onclick: this.props.onclick
}, m('div.post-preview-content', [
avatar(user), ' ',
username(user), ' ',
humanTime(post.time()), ' ',
post.excerpt()
]));
}
}

View File

@ -12,6 +12,7 @@ Post.prototype.user = Model.one('user');
Post.prototype.contentType = Model.prop('contentType'); Post.prototype.contentType = Model.prop('contentType');
Post.prototype.content = Model.prop('content'); Post.prototype.content = Model.prop('content');
Post.prototype.contentHtml = Model.prop('contentHtml'); Post.prototype.contentHtml = Model.prop('contentHtml');
Post.prototype.excerpt = Model.prop('excerpt');
Post.prototype.editTime = Model.prop('editTime', Model.date); Post.prototype.editTime = Model.prop('editTime', Model.date);
Post.prototype.editUser = Model.one('editUser'); Post.prototype.editUser = Model.one('editUser');

View File

@ -338,6 +338,29 @@
} }
} }
.post-preview {
color: @fl-body-muted-color;
padding-left: 50px;
line-height: 1.7em;
& .avatar {
float: left;
margin-left: -50px;
.avatar-size(32px);
}
& .username {
color: @fl-body-color;
font-weight: bold;
margin-right: 5px;
}
& time {
margin-right: 5px;
text-transform: uppercase;
font-size: 11px;
font-weight: 600;
}
}
@media @phone { @media @phone {
.post-header { .post-header {
& .avatar { & .avatar {

View File

@ -39,7 +39,7 @@ class PostBasicSerializer extends BaseSerializer
]; ];
if ($post->type === 'comment') { if ($post->type === 'comment') {
$attributes['content'] = str_limit($post->content, 200); $attributes['excerpt'] = str_limit($post->contentPlain, 200);
} else { } else {
$attributes['content'] = $post->content; $attributes['content'] = $post->content;
} }

View File

@ -26,16 +26,6 @@ class FormatterManager
public function add($name, $formatter, $priority = 0) public function add($name, $formatter, $priority = 0)
{ {
$this->remove($name);
if (is_string($formatter)) {
$formatter = function () use ($formatter) {
$callable = array($this->container->make($formatter), 'format');
$data = func_get_args();
return call_user_func_array($callable, $data);
};
}
$this->formatters[$name] = [$formatter, $priority]; $this->formatters[$name] = [$formatter, $priority];
} }
@ -44,23 +34,44 @@ class FormatterManager
unset($this->formatters[$name]); unset($this->formatters[$name]);
} }
public function format($text) protected function getFormatters()
{
$sorted = [];
foreach ($this->formatters as $array) {
list($formatter, $priority) = $array;
$sorted[$priority][] = $formatter;
}
ksort($sorted);
$result = [];
foreach ($sorted as $formatters) {
$result = array_merge($result, $formatters);
}
return $result;
}
public function format($text, $post = null)
{ {
$sorted = []; foreach ($this->getFormatters() as $formatter) {
$text = $this->container->make($formatter)->format($text, $post);
foreach ($this->formatters as $array) {
list($formatter, $priority) = $array;
$sorted[$priority][] = $formatter;
}
ksort($sorted);
foreach ($sorted as $formatters) {
foreach ($formatters as $formatter) {
$text = $formatter($text);
}
} }
return $text; return $text;
} }
public function strip($text)
{
foreach ($this->getFormatters() as $formatter) {
$formatter = $this->container->make($formatter);
if (method_exists($formatter, 'strip')) {
$text = $formatter->strip($text);
}
}
return $text;
}
} }

View File

@ -35,7 +35,6 @@ class CommentPost extends Post
$post = new static; $post = new static;
$post->content = $content; $post->content = $content;
$post->content_html = static::formatContent($post->content);
$post->time = time(); $post->time = time();
$post->discussion_id = $discussionId; $post->discussion_id = $discussionId;
$post->user_id = $userId; $post->user_id = $userId;
@ -57,7 +56,7 @@ class CommentPost extends Post
{ {
if ($this->content !== $content) { if ($this->content !== $content) {
$this->content = $content; $this->content = $content;
$this->content_html = static::formatContent($this->content); $this->content_html = static::formatContent($this);
$this->edit_time = time(); $this->edit_time = time();
$this->edit_user_id = $user->id; $this->edit_user_id = $user->id;
@ -113,13 +112,24 @@ class CommentPost extends Post
public function getContentHtmlAttribute($value) public function getContentHtmlAttribute($value)
{ {
if (! $value) { if (! $value) {
$this->content_html = $value = static::formatContent($this->content); $this->content_html = $value = static::formatContent($this);
$this->save(); $this->save();
} }
return $value; return $value;
} }
/**
* Get the content formatter as HTML.
*
* @param string $value
* @return string
*/
public function getContentPlainAttribute()
{
return static::$formatter->strip($this->content);
}
/** /**
* Get text formatter instance. * Get text formatter instance.
* *
@ -146,8 +156,8 @@ class CommentPost extends Post
* @param string $content * @param string $content
* @return string * @return string
*/ */
protected static function formatContent($content) protected static function formatContent($post)
{ {
return static::$formatter->format($content); return static::$formatter->format($post->content, $post);
} }
} }