From 42851f425b29b123805b49c81c7e1ae4e620f272 Mon Sep 17 00:00:00 2001 From: Toby Zerner Date: Thu, 4 Jun 2015 10:48:07 +0930 Subject: [PATCH] Rejig formatting API. closes flarum/core#85 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It works but it’s not the most pretty thing in the world. @franzliedke Would be great if you could take a look at the whole formatting API and work your magic on it sometime… my brain is fried! --- js/forum/src/components/post-preview.js | 16 ++++++- js/lib/models/post.js | 2 +- src/Api/Serializers/PostBasicSerializer.php | 2 +- src/Core/Formatter/FormatterAbstract.php | 48 +++++++++++++++++++++ src/Core/Formatter/FormatterInterface.php | 10 +++++ src/Core/Formatter/FormatterManager.php | 19 ++++---- src/Core/Formatter/LinkifyFormatter.php | 5 ++- src/Core/Models/CommentPost.php | 11 ----- 8 files changed, 87 insertions(+), 26 deletions(-) create mode 100644 src/Core/Formatter/FormatterAbstract.php create mode 100644 src/Core/Formatter/FormatterInterface.php 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('``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. *