diff --git a/js/forum/src/components/post-preview.js b/js/forum/src/components/post-preview.js
index 3318defc0..592916cb9 100644
--- a/js/forum/src/components/post-preview.js
+++ b/js/forum/src/components/post-preview.js
@@ -9,6 +9,20 @@ export default class PostPreview extends Component {
var post = this.props.post;
var user = post.user();
+ var excerpt = post.contentPlain();
+ var start = 0;
+
+ if (highlight) {
+ var regexp = new RegExp(this.props.highlight, 'gi');
+ start = Math.max(0, excerpt.search(regexp) - 100);
+ }
+
+ excerpt = (start > 0 ? '...' : '')+excerpt.substring(start, start + 200)+(excerpt.length > start + 200 ? '...' : '');
+
+ if (highlight) {
+ excerpt = highlight(excerpt, regexp);
+ }
+
return m('a.post-preview', {
href: app.route.post(post),
config: m.route,
@@ -17,7 +31,7 @@ export default class PostPreview extends Component {
avatar(user), ' ',
username(user), ' ',
humanTime(post.time()), ' ',
- highlight(post.excerpt(), this.props.highlight)
+ excerpt
]));
}
}
diff --git a/js/lib/models/post.js b/js/lib/models/post.js
index 0ac3f4787..671e3e91d 100644
--- a/js/lib/models/post.js
+++ b/js/lib/models/post.js
@@ -12,7 +12,7 @@ Post.prototype.user = Model.one('user');
Post.prototype.contentType = Model.prop('contentType');
Post.prototype.content = Model.prop('content');
Post.prototype.contentHtml = Model.prop('contentHtml');
-Post.prototype.excerpt = Model.prop('excerpt');
+Post.prototype.contentPlain = computed('contentHtml', contentHtml => $('
').html(contentHtml.replace(/(<\/p>|
)/g, '$1 ')).text());
Post.prototype.editTime = Model.prop('editTime', Model.date);
Post.prototype.editUser = Model.one('editUser');
diff --git a/src/Api/Serializers/PostBasicSerializer.php b/src/Api/Serializers/PostBasicSerializer.php
index 92370541e..25aa96518 100644
--- a/src/Api/Serializers/PostBasicSerializer.php
+++ b/src/Api/Serializers/PostBasicSerializer.php
@@ -25,7 +25,7 @@ class PostBasicSerializer extends BaseSerializer
];
if ($post->type === 'comment') {
- $attributes['excerpt'] = str_limit($post->contentPlain, 200);
+ $attributes['contentHtml'] = $post->content_html;
} else {
$attributes['content'] = $post->content;
}
diff --git a/src/Core/Formatter/FormatterAbstract.php b/src/Core/Formatter/FormatterAbstract.php
new file mode 100644
index 000000000..27cb84b48
--- /dev/null
+++ b/src/Core/Formatter/FormatterAbstract.php
@@ -0,0 +1,48 @@
+)/is', $text, 0, PREG_SPLIT_DELIM_CAPTURE);
+
+ $openTag = null;
+
+ for ($i = 0; $i < count($chunks); $i++) {
+ if ($i % 2 === 0) { // even numbers are text
+ // Only process this chunk if there are no unclosed $ignoreTags
+ if (null === $openTag) {
+ $chunks[$i] = $callback($chunks[$i]);
+ }
+ } else { // odd numbers are tags
+ // Only process this tag if there are no unclosed $ignoreTags
+ if (null === $openTag) {
+ // Check whether this tag is contained in $ignoreTags and is not self-closing
+ if (preg_match("`<(" . implode('|', $tags) . ").*(?$`is", $chunks[$i], $matches)) {
+ $openTag = $matches[1];
+ }
+ } else {
+ // Otherwise, check whether this is the closing tag for $openTag.
+ if (preg_match('`\s*' . $openTag . '>`i', $chunks[$i], $matches)) {
+ $openTag = null;
+ }
+ }
+ }
+ }
+
+ return implode($chunks);
+ }
+}
diff --git a/src/Core/Formatter/FormatterInterface.php b/src/Core/Formatter/FormatterInterface.php
new file mode 100644
index 000000000..0a09c5fc8
--- /dev/null
+++ b/src/Core/Formatter/FormatterInterface.php
@@ -0,0 +1,10 @@
+getFormatters() as $formatter) {
- $text = $this->container->make($formatter)->format($text, $post);
+ $formatters[] = $this->container->make($formatter);
+ }
+
+ foreach ($formatters as $formatter) {
+ $text = $formatter->beforePurification($text, $post);
}
// Studio does not yet merge autoload_files...
@@ -75,16 +80,10 @@ class FormatterManager
$purifier = new HTMLPurifier($config);
- return $purifier->purify($text);
- }
+ $text = $purifier->purify($text);
- public function strip($text)
- {
- foreach ($this->getFormatters() as $formatter) {
- $formatter = $this->container->make($formatter);
- if (method_exists($formatter, 'strip')) {
- $text = $formatter->strip($text);
- }
+ foreach ($formatters as $formatter) {
+ $text = $formatter->afterPurification($text, $post);
}
return $text;
diff --git a/src/Core/Formatter/LinkifyFormatter.php b/src/Core/Formatter/LinkifyFormatter.php
index be5570f29..5b616ecd7 100644
--- a/src/Core/Formatter/LinkifyFormatter.php
+++ b/src/Core/Formatter/LinkifyFormatter.php
@@ -1,8 +1,9 @@
linkify = $linkify;
}
- public function format($text)
+ public function beforePurification($text, Post $post = null)
{
return $this->linkify->process($text, ['attr' => ['target' => '_blank']]);
}
diff --git a/src/Core/Models/CommentPost.php b/src/Core/Models/CommentPost.php
index 7d1bbf9de..2c63f695e 100755
--- a/src/Core/Models/CommentPost.php
+++ b/src/Core/Models/CommentPost.php
@@ -119,17 +119,6 @@ class CommentPost extends Post
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.
*