mirror of
https://github.com/flarum/framework.git
synced 2024-11-29 04:33:47 +08:00
Update to sub in "display names" from database when rendering
This also improves the behaviour of mentions in the JS preview (no more broken links, mention is only picked up if corresponding user/post is found). See flarum/core#1246 Closes flarum/core#315
This commit is contained in:
parent
acd3195491
commit
408d882598
69
extensions/mentions/js/forum/dist/extension.js
vendored
69
extensions/mentions/js/forum/dist/extension.js
vendored
|
@ -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 () {}
|
||||
};
|
||||
});
|
|
@ -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 => {
|
||||
|
|
|
@ -67,5 +67,6 @@ app.initializers.add('flarum-mentions', function() {
|
|||
);
|
||||
});
|
||||
|
||||
// Remove post mentions when rendering post previews.
|
||||
getPlainContent.removeSelectors.push('a.PostMention');
|
||||
});
|
||||
|
|
25
extensions/mentions/js/forum/src/utils/textFormatter.js
Normal file
25
extensions/mentions/js/forum/src/utils/textFormatter.js
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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\GetApiRelationship;
|
|||
use Flarum\Event\GetModelRelationship;
|
||||
use Flarum\Event\PrepareApiData;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class AddPostMentionedByRelationship
|
||||
{
|
||||
|
@ -94,7 +93,7 @@ class AddPostMentionedByRelationship
|
|||
*/
|
||||
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 @@ class AddPostMentionedByRelationship
|
|||
]);
|
||||
}
|
||||
|
||||
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 @@ class AddPostMentionedByRelationship
|
|||
]);
|
||||
}
|
||||
|
||||
if ($event->isController(CreatePostController::class)) {
|
||||
if ($event->isController(Controller\CreatePostController::class)) {
|
||||
$event->addInclude([
|
||||
'mentionsPosts',
|
||||
'mentionsPosts.mentionedBy'
|
||||
|
@ -133,22 +132,33 @@ class AddPostMentionedByRelationship
|
|||
{
|
||||
// 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());
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use Flarum\Event\ConfigureFormatter;
|
|||
use Flarum\Event\ConfigureFormatterRenderer;
|
||||
use Flarum\Forum\UrlGenerator;
|
||||
use Illuminate\Contracts\Events\Dispatcher;
|
||||
use s9e\TextFormatter\Utils;
|
||||
|
||||
class FormatPostMentions
|
||||
{
|
||||
|
@ -48,22 +49,23 @@ class FormatPostMentions
|
|||
{
|
||||
$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 = '<a href="{$DISCUSSION_URL}{@discussionid}/{@number}" class="PostMention" data-id="{@id}"><xsl:value-of select="@username"/></a>';
|
||||
$tag->template = '<a href="{$DISCUSSION_URL}{@discussionid}/{@number}" class="PostMention" data-id="{@id}"><xsl:value-of select="@displayname"/></a>';
|
||||
|
||||
$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@(?<username>[a-z0-9_-]+)#(?<id>\d+)/i', $tagName);
|
||||
}
|
||||
|
@ -73,7 +75,15 @@ class FormatPostMentions
|
|||
*/
|
||||
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 @@ class FormatPostMentions
|
|||
if ($post) {
|
||||
$tag->setAttribute('discussionid', (int) $post->discussion_id);
|
||||
$tag->setAttribute('number', (int) $post->number);
|
||||
$tag->setAttribute('displayname', $post->user->display_name);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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 @@ class FormatUserMentions
|
|||
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 @@ class FormatUserMentions
|
|||
{
|
||||
$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 = '<a href="{$PROFILE_URL}{@username}" class="UserMention">@<xsl:value-of select="@username"/></a>';
|
||||
$tag->template = '<a href="{$PROFILE_URL}{@username}" class="UserMention">@<xsl:value-of select="@displayname"/></a>';
|
||||
$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@(?<username>[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 @@ class FormatUserMentions
|
|||
* @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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user