diff --git a/js/forum/dist/extension.js b/js/forum/dist/extension.js
index 5a089ea..8e6668a 100644
--- a/js/forum/dist/extension.js
+++ b/js/forum/dist/extension.js
@@ -179,14 +179,12 @@ System.register('flarum/mentions/addComposerAutocomplete', ['flarum/extend', 'fl
if (this.selectionEnd - cursor > 0) return;
- // Search backwards from the cursor for an '@' symbol, without any
- // intervening whitespace. If we find one, we will want to show the
- // autocomplete dropdown!
+ // Search backwards from the cursor for an '@' symbol. If we find one,
+ // we will want to show the autocomplete dropdown!
var value = this.value;
mentionStart = 0;
- for (var i = cursor - 1; i >= 0; i--) {
+ for (var i = cursor - 1; i >= cursor - 30; i--) {
var character = value.substr(i, 1);
- if (/\s/.test(character)) break;
if (character === '@') {
mentionStart = i + 1;
break;
@@ -228,6 +226,14 @@ System.register('flarum/mentions/addComposerAutocomplete', ['flarum/extend', 'fl
);
};
+ var userMatches = function userMatches(user) {
+ var names = [user.username(), user.displayName()];
+
+ return names.some(function (value) {
+ return value.toLowerCase().substr(0, typed.length) === typed;
+ });
+ };
+
var buildSuggestions = function buildSuggestions() {
var suggestions = [];
@@ -235,7 +241,7 @@ System.register('flarum/mentions/addComposerAutocomplete', ['flarum/extend', 'fl
// matching that username.
if (typed) {
app.store.all('users').forEach(function (user) {
- if (user.username().toLowerCase().substr(0, typed.length) !== typed) return;
+ if (!userMatches(user)) return;
suggestions.push(makeSuggestion(user, '@' + user.username(), '', 'MentionsDropdown-user'));
});
@@ -254,7 +260,7 @@ System.register('flarum/mentions/addComposerAutocomplete', ['flarum/extend', 'fl
return b.time() - a.time();
}).filter(function (post) {
var user = post.user();
- return user && user.username().toLowerCase().substr(0, typed.length) === typed;
+ return user && userMatches(user);
}).splice(0, 5).forEach(function (post) {
var user = post.user();
suggestions.push(makeSuggestion(user, '@' + user.username() + '#' + post.id(), [app.translator.trans('flarum-mentions.forum.composer.reply_to_post_text', { number: post.number() }), ' — ', truncate(post.contentPlain(), 200)], 'MentionsDropdown-post'));
@@ -279,14 +285,18 @@ System.register('flarum/mentions/addComposerAutocomplete', ['flarum/extend', 'fl
left = parent.width() - width;
}
dropdown.show(left, top);
+ } else {
+ dropdown.active = false;
+ dropdown.hide();
}
};
+ dropdown.active = true;
+
buildSuggestions();
dropdown.setIndex(0);
dropdown.$().scrollTop(0);
- dropdown.active = true;
clearTimeout(searchTimeout);
if (typed) {
@@ -1166,6 +1176,7 @@ System.register('flarum/mentions/main', ['flarum/extend', 'flarum/app', 'flarum/
}), 80);
});
+ // Remove post mentions when rendering post previews.
getPlainContent.removeSelectors.push('a.PostMention');
});
}
@@ -1258,4 +1269,46 @@ System.register('flarum/mentions/utils/selectedText', [], function (_export, _co
setters: [],
execute: function () {}
};
+});;
+'use strict';
+
+System.register('flarum/mentions/utils/textFormatter', ['flarum/helpers/username', 'flarum/utils/extractText'], function (_export, _context) {
+ "use strict";
+
+ var username, extractText;
+ function filterUserMentions(tag) {
+ var user = app.store.getBy('users', 'username', tag.getAttribute('username'));
+
+ if (user) {
+ tag.setAttribute('id', user.id());
+ tag.setAttribute('displayname', extractText(username(user)));
+
+ return true;
+ }
+ }
+
+ _export('filterUserMentions', filterUserMentions);
+
+ function filterPostMentions(tag) {
+ var post = app.store.getById('posts', tag.getAttribute('id'));
+
+ if (post) {
+ tag.setAttribute('discussionid', post.discussion().id());
+ tag.setAttribute('number', post.number());
+ tag.setAttribute('displayname', extractText(username(post.user())));
+
+ return true;
+ }
+ }
+
+ _export('filterPostMentions', filterPostMentions);
+
+ return {
+ setters: [function (_flarumHelpersUsername) {
+ username = _flarumHelpersUsername.default;
+ }, function (_flarumUtilsExtractText) {
+ extractText = _flarumUtilsExtractText.default;
+ }],
+ execute: function () {}
+ };
});
\ No newline at end of file
diff --git a/js/forum/src/addComposerAutocomplete.js b/js/forum/src/addComposerAutocomplete.js
index d5d7afd..98c589d 100644
--- a/js/forum/src/addComposerAutocomplete.js
+++ b/js/forum/src/addComposerAutocomplete.js
@@ -54,14 +54,12 @@ export default function addComposerAutocomplete() {
if (this.selectionEnd - cursor > 0) return;
- // Search backwards from the cursor for an '@' symbol, without any
- // intervening whitespace. If we find one, we will want to show the
- // autocomplete dropdown!
+ // Search backwards from the cursor for an '@' symbol. If we find one,
+ // we will want to show the autocomplete dropdown!
const value = this.value;
mentionStart = 0;
- for (let i = cursor - 1; i >= 0; i--) {
+ for (let i = cursor - 1; i >= cursor - 30; i--) {
const character = value.substr(i, 1);
- if (/\s/.test(character)) break;
if (character === '@') {
mentionStart = i + 1;
break;
@@ -95,6 +93,15 @@ export default function addComposerAutocomplete() {
);
};
+ const userMatches = function(user) {
+ const names = [
+ user.username(),
+ user.displayName()
+ ];
+
+ return names.some(value => value.toLowerCase().substr(0, typed.length) === typed);
+ };
+
const buildSuggestions = () => {
const suggestions = [];
@@ -102,7 +109,7 @@ export default function addComposerAutocomplete() {
// matching that username.
if (typed) {
app.store.all('users').forEach(user => {
- if (user.username().toLowerCase().substr(0, typed.length) !== typed) return;
+ if (!userMatches(user)) return;
suggestions.push(
makeSuggestion(user, '@' + user.username(), '', 'MentionsDropdown-user')
@@ -122,7 +129,7 @@ export default function addComposerAutocomplete() {
.sort((a, b) => b.time() - a.time())
.filter(post => {
const user = post.user();
- return user && user.username().toLowerCase().substr(0, typed.length) === typed;
+ return user && userMatches(user);
})
.splice(0, 5)
.forEach(post => {
diff --git a/js/forum/src/main.js b/js/forum/src/main.js
index de8cc4f..181375b 100644
--- a/js/forum/src/main.js
+++ b/js/forum/src/main.js
@@ -67,5 +67,6 @@ app.initializers.add('flarum-mentions', function() {
);
});
+ // Remove post mentions when rendering post previews.
getPlainContent.removeSelectors.push('a.PostMention');
});
diff --git a/js/forum/src/utils/textFormatter.js b/js/forum/src/utils/textFormatter.js
new file mode 100644
index 0000000..747a490
--- /dev/null
+++ b/js/forum/src/utils/textFormatter.js
@@ -0,0 +1,25 @@
+import username from 'flarum/helpers/username';
+import extractText from 'flarum/utils/extractText';
+
+export function filterUserMentions(tag) {
+ const user = app.store.getBy('users', 'username', tag.getAttribute('username'));
+
+ if (user) {
+ tag.setAttribute('id', user.id());
+ tag.setAttribute('displayname', extractText(username(user)));
+
+ return true;
+ }
+}
+
+export function filterPostMentions(tag) {
+ const post = app.store.getById('posts', tag.getAttribute('id'));
+
+ if (post) {
+ tag.setAttribute('discussionid', post.discussion().id());
+ tag.setAttribute('number', post.number());
+ tag.setAttribute('displayname', extractText(username(post.user())));
+
+ return true;
+ }
+}
diff --git a/src/Listener/AddPostMentionedByRelationship.php b/src/Listener/AddPostMentionedByRelationship.php
index d0d3596..4c7a735 100755
--- a/src/Listener/AddPostMentionedByRelationship.php
+++ b/src/Listener/AddPostMentionedByRelationship.php
@@ -11,12 +11,10 @@
namespace Flarum\Mentions\Listener;
-use Flarum\Api\Controller\CreatePostController;
-use Flarum\Api\Controller\ListPostsController;
-use Flarum\Api\Controller\ShowDiscussionController;
-use Flarum\Api\Controller\ShowPostController;
+use Flarum\Api\Controller;
use Flarum\Api\Serializer\PostBasicSerializer;
use Flarum\Core\Post;
+use Flarum\Core\Post\CommentPost;
use Flarum\Core\Repository\PostRepository;
use Flarum\Core\User;
use Flarum\Event\ConfigureApiController;
@@ -24,6 +22,7 @@
use Flarum\Event\GetModelRelationship;
use Flarum\Event\PrepareApiData;
use Illuminate\Contracts\Events\Dispatcher;
+use Illuminate\Database\Eloquent\Collection;
class AddPostMentionedByRelationship
{
@@ -94,7 +93,7 @@ public function getApiRelationship(GetApiRelationship $event)
*/
public function includeRelationships(ConfigureApiController $event)
{
- if ($event->isController(ShowDiscussionController::class)) {
+ if ($event->isController(Controller\ShowDiscussionController::class)) {
$event->addInclude([
'posts.mentionedBy',
'posts.mentionedBy.user',
@@ -102,8 +101,8 @@ public function includeRelationships(ConfigureApiController $event)
]);
}
- if ($event->isController(ShowPostController::class)
- || $event->isController(ListPostsController::class)) {
+ if ($event->isController(Controller\ShowPostController::class)
+ || $event->isController(Controller\ListPostsController::class)) {
$event->addInclude([
'mentionedBy',
'mentionedBy.user',
@@ -111,7 +110,7 @@ public function includeRelationships(ConfigureApiController $event)
]);
}
- if ($event->isController(CreatePostController::class)) {
+ if ($event->isController(Controller\CreatePostController::class)) {
$event->addInclude([
'mentionsPosts',
'mentionsPosts.mentionedBy'
@@ -133,22 +132,33 @@ public function filterVisiblePosts(PrepareApiData $event)
{
// Firstly we gather a list of posts contained within the API document.
// This will vary according to the API endpoint that is being accessed.
- if ($event->isController(ShowDiscussionController::class)) {
+ if ($event->isController(Controller\ShowDiscussionController::class)) {
$posts = $event->data->posts;
- } elseif ($event->isController(ShowPostController::class)) {
+ } elseif ($event->isController(Controller\ShowPostController::class)
+ || $event->isController(Controller\CreatePostController::class)
+ || $event->isController(Controller\UpdatePostController::class)) {
$posts = [$event->data];
- } elseif ($event->isController(ListPostsController::class)) {
+ } elseif ($event->isController(Controller\ListPostsController::class)) {
$posts = $event->data;
}
if (isset($posts)) {
- $posts = array_filter((array) $posts, 'is_object');
+ $posts = new Collection($posts);
+
+ $posts = $posts->filter(function ($post) {
+ return $post instanceof CommentPost;
+ });
+
+ // Load all of the users that these posts mention. This way the data
+ // will be ready to go when we need to sub in current usernames
+ // during the rendering process.
+ $posts->load(['mentionsUsers', 'mentionsPosts.user']);
+
+ // Construct a list of the IDs of all of the posts that these posts
+ // have been mentioned in. We can then filter this list of IDs to
+ // weed out all of the ones which the user is not meant to see.
$ids = [];
- // Once we have the posts, construct a list of the IDs of all of
- // the posts that they have been mentioned in. We can then filter
- // this list of IDs to weed out all of the ones which the user is
- // not meant to see.
foreach ($posts as $post) {
$ids = array_merge($ids, $post->mentionedBy->pluck('id')->all());
}
diff --git a/src/Listener/FormatPostMentions.php b/src/Listener/FormatPostMentions.php
index 888da12..9731303 100755
--- a/src/Listener/FormatPostMentions.php
+++ b/src/Listener/FormatPostMentions.php
@@ -16,6 +16,7 @@
use Flarum\Event\ConfigureFormatterRenderer;
use Flarum\Forum\UrlGenerator;
use Illuminate\Contracts\Events\Dispatcher;
+use s9e\TextFormatter\Utils;
class FormatPostMentions
{
@@ -48,22 +49,23 @@ public function configure(ConfigureFormatter $event)
{
$configurator = $event->configurator;
+ $configurator->rendering->parameters['DISCUSSION_URL'] = $this->url->toRoute('discussion', ['id' => '']);
+
$tagName = 'POSTMENTION';
$tag = $configurator->tags->add($tagName);
$tag->attributes->add('username');
+ $tag->attributes->add('displayname');
$tag->attributes->add('number')->filterChain->append('#uint');
$tag->attributes->add('discussionid')->filterChain->append('#uint');
$tag->attributes->add('id')->filterChain->append('#uint');
- $tag->attributes['number']->required = false;
- $tag->attributes['discussionid']->required = false;
- $tag->template = '';
+ $tag->template = '';
$tag->filterChain
->prepend([static::class, 'addId'])
- ->setJS('function() { return true; }');
+ ->setJS('function(tag) { return System.get("flarum/mentions/utils/textFormatter").filterPostMentions(tag); }');
$configurator->Preg->match('/\B@(?[a-z0-9_-]+)#(?\d+)/i', $tagName);
}
@@ -73,7 +75,15 @@ public function configure(ConfigureFormatter $event)
*/
public function render(ConfigureFormatterRenderer $event)
{
- $event->renderer->setParameter('DISCUSSION_URL', $this->url->toRoute('discussion', ['id' => '']));
+ $post = $event->context;
+
+ $event->xml = Utils::replaceAttributes($event->xml, 'POSTMENTION', function ($attributes) use ($post) {
+ $post = $post->mentionsPosts->find($attributes['id']);
+ if ($post && $post->user) {
+ $attributes['displayname'] = $post->user->display_name;
+ }
+ return $attributes;
+ });
}
/**
@@ -87,6 +97,7 @@ public static function addId($tag)
if ($post) {
$tag->setAttribute('discussionid', (int) $post->discussion_id);
$tag->setAttribute('number', (int) $post->number);
+ $tag->setAttribute('displayname', $post->user->display_name);
return true;
}
diff --git a/src/Listener/FormatUserMentions.php b/src/Listener/FormatUserMentions.php
index 28b279a..83863f0 100755
--- a/src/Listener/FormatUserMentions.php
+++ b/src/Listener/FormatUserMentions.php
@@ -11,32 +11,25 @@
namespace Flarum\Mentions\Listener;
-use Flarum\Core\Repository\UserRepository;
+use Flarum\Core\User;
use Flarum\Event\ConfigureFormatter;
-use Flarum\Event\ConfigureFormatterParser;
use Flarum\Event\ConfigureFormatterRenderer;
use Flarum\Forum\UrlGenerator;
use Illuminate\Contracts\Events\Dispatcher;
+use s9e\TextFormatter\Utils;
class FormatUserMentions
{
- /**
- * @var UserRepository
- */
- protected $users;
-
/**
* @var UrlGenerator
*/
protected $url;
/**
- * @param UserRepository $users
* @param UrlGenerator $url
*/
- public function __construct(UserRepository $users, UrlGenerator $url)
+ public function __construct(UrlGenerator $url)
{
- $this->users = $users;
$this->url = $url;
}
@@ -46,7 +39,6 @@ public function __construct(UserRepository $users, UrlGenerator $url)
public function subscribe(Dispatcher $events)
{
$events->listen(ConfigureFormatter::class, [$this, 'configure']);
- $events->listen(ConfigureFormatterParser::class, [$this, 'parse']);
$events->listen(ConfigureFormatterRenderer::class, [$this, 'render']);
}
@@ -57,35 +49,37 @@ public function configure(ConfigureFormatter $event)
{
$configurator = $event->configurator;
+ $configurator->rendering->parameters['PROFILE_URL'] = $this->url->toRoute('user', ['username' => '']);
+
$tagName = 'USERMENTION';
$tag = $configurator->tags->add($tagName);
$tag->attributes->add('username');
+ $tag->attributes->add('displayname');
$tag->attributes->add('id')->filterChain->append('#uint');
- $tag->attributes['id']->required = false;
- $tag->template = '@';
+ $tag->template = '@';
$tag->filterChain->prepend([static::class, 'addId'])
->addParameterByName('userRepository')
- ->setJS('function() { return true; }');
+ ->setJS('function(tag) { return System.get("flarum/mentions/utils/textFormatter").filterUserMentions(tag); }');
$configurator->Preg->match('/\B@(?[a-z0-9_-]+)(?!#)/i', $tagName);
}
- /**
- * @param ConfigureFormatterParser $event
- */
- public function parse(ConfigureFormatterParser $event)
- {
- $event->parser->registeredVars['userRepository'] = $this->users;
- }
-
/**
* @param ConfigureFormatterRenderer $event
*/
public function render(ConfigureFormatterRenderer $event)
{
- $event->renderer->setParameter('PROFILE_URL', $this->url->toRoute('user', ['username' => '']));
+ $post = $event->context;
+
+ $event->xml = Utils::replaceAttributes($event->xml, 'USERMENTION', function ($attributes) use ($post) {
+ $user = $post->mentionsUsers->find($attributes['id']);
+ if ($user) {
+ $attributes['displayname'] = $user->display_name;
+ }
+ return $attributes;
+ });
}
/**
@@ -93,10 +87,11 @@ public function render(ConfigureFormatterRenderer $event)
* @param UserRepository $users
* @return bool
*/
- public static function addId($tag, UserRepository $users)
+ public static function addId($tag)
{
- if ($id = $users->getIdForUsername($tag->getAttribute('username'))) {
- $tag->setAttribute('id', $id);
+ if ($user = User::where('username', 'like', $tag->getAttribute('username'))->first()) {
+ $tag->setAttribute('id', $user->id);
+ $tag->setAttribute('displayname', $user->display_name);
return true;
}