Compare commits
15 Commits
v1.0.0-alp
...
1.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e5d25686c | ||
|
|
bbba63c57b | ||
|
|
f9f9950cde | ||
|
|
bb88583f09 | ||
|
|
4b783e437f | ||
|
|
d189743a9c | ||
|
|
541d11ab90 | ||
|
|
48fbd3c9d7 | ||
|
|
e7daa25fc2 | ||
|
|
bff68f87a3 | ||
|
|
583b49125f | ||
|
|
5e44a4051a | ||
|
|
812556cba2 | ||
|
|
20dba18e8e | ||
|
|
a5bf29d6c2 |
15
CHANGELOG.md
15
CHANGELOG.md
@@ -4,3 +4,18 @@ All notable changes to this project will be documented in this file.
|
|||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## v1.0.0-alpha.4 - 2026-03-31
|
||||||
|
|
||||||
|
<!-- Release notes generated using configuration in .github/release.yml at 1.x -->
|
||||||
|
### What's Changed
|
||||||
|
|
||||||
|
#### Other Changes
|
||||||
|
|
||||||
|
* fix: show reply instantly after adding without page refresh by @Ilyapashayan20 in https://github.com/relaticle/comments/pull/10
|
||||||
|
|
||||||
|
### New Contributors
|
||||||
|
|
||||||
|
* @Ilyapashayan20 made their first contribution in https://github.com/relaticle/comments/pull/10
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/relaticle/comments/compare/v1.0.0-alpha.3...v1.0.0-alpha.4
|
||||||
|
|||||||
18
resources/css/comments.css
Normal file
18
resources/css/comments.css
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
.comment-mention {
|
||||||
|
background-color: rgb(var(--primary-50));
|
||||||
|
color: rgb(var(--primary-600));
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
display: inline-block;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding-left: 0.25rem;
|
||||||
|
padding-right: 0.25rem;
|
||||||
|
font-weight: 500;
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: background-color 0.15s ease, color 0.15s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark .comment-mention {
|
||||||
|
background-color: rgb(var(--primary-400) / 0.1);
|
||||||
|
color: rgb(var(--primary-400));
|
||||||
|
}
|
||||||
@@ -104,7 +104,11 @@
|
|||||||
|
|
||||||
{{-- Reply form --}}
|
{{-- Reply form --}}
|
||||||
@if ($isReplying)
|
@if ($isReplying)
|
||||||
<div class="mt-3">
|
<div class="mt-3"
|
||||||
|
x-data="{ uploadError: null }"
|
||||||
|
x-on:livewire-upload-error.window="uploadError = '{{ __('File upload failed. The file may be too large or an unsupported type.') }}'"
|
||||||
|
x-on:livewire-upload-start.window="uploadError = null"
|
||||||
|
>
|
||||||
{{ $this->replyForm }}
|
{{ $this->replyForm }}
|
||||||
|
|
||||||
@if (!empty($replyAttachments))
|
@if (!empty($replyAttachments))
|
||||||
@@ -120,6 +124,7 @@
|
|||||||
@error('replyAttachments.*')
|
@error('replyAttachments.*')
|
||||||
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
||||||
@enderror
|
@enderror
|
||||||
|
<p x-show="uploadError" x-text="uploadError" class="mt-1 text-sm text-danger-600 dark:text-danger-400"></p>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="mt-2 flex items-center justify-between">
|
<div class="mt-2 flex items-center justify-between">
|
||||||
|
|||||||
@@ -2,11 +2,14 @@
|
|||||||
@if (!\Relaticle\Comments\CommentsConfig::isBroadcastingEnabled())
|
@if (!\Relaticle\Comments\CommentsConfig::isBroadcastingEnabled())
|
||||||
wire:poll.{{ \Relaticle\Comments\CommentsConfig::getPollingInterval() }}
|
wire:poll.{{ \Relaticle\Comments\CommentsConfig::getPollingInterval() }}
|
||||||
@endif
|
@endif
|
||||||
|
x-data="{ uploadError: null }"
|
||||||
|
x-on:livewire-upload-error.window="uploadError = '{{ __('File upload failed. The file may be too large or an unsupported type.') }}'"
|
||||||
|
x-on:livewire-upload-start.window="uploadError = null"
|
||||||
>
|
>
|
||||||
{{-- Sort toggle --}}
|
{{-- Sort toggle --}}
|
||||||
<div class="flex items-center justify-between">
|
<div class="flex items-center justify-between">
|
||||||
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
<h3 class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
||||||
Comments ({{ $this->totalCount }})
|
Comments ({{ $this->allCommentsCount }})
|
||||||
</h3>
|
</h3>
|
||||||
@auth
|
@auth
|
||||||
<div class="flex items-center gap-3">
|
<div class="flex items-center gap-3">
|
||||||
@@ -76,6 +79,7 @@
|
|||||||
@error('attachments.*')
|
@error('attachments.*')
|
||||||
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
<p class="mt-1 text-sm text-danger-600 dark:text-danger-400">{{ $message }}</p>
|
||||||
@enderror
|
@enderror
|
||||||
|
<p x-show="uploadError" x-text="uploadError" class="mt-1 text-sm text-danger-600 dark:text-danger-400"></p>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
<div class="mt-2 flex items-center justify-between">
|
<div class="mt-2 flex items-center justify-between">
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Relaticle\Comments;
|
namespace Relaticle\Comments;
|
||||||
|
|
||||||
|
use Filament\Support\Assets\Css;
|
||||||
|
use Filament\Support\Facades\FilamentAsset;
|
||||||
use Illuminate\Database\Eloquent\Relations\Relation;
|
use Illuminate\Database\Eloquent\Relations\Relation;
|
||||||
use Illuminate\Support\Facades\Event;
|
use Illuminate\Support\Facades\Event;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
@@ -16,6 +18,8 @@ use Relaticle\Comments\Livewire\Comments;
|
|||||||
use Relaticle\Comments\Livewire\Reactions;
|
use Relaticle\Comments\Livewire\Reactions;
|
||||||
use Spatie\LaravelPackageTools\Package;
|
use Spatie\LaravelPackageTools\Package;
|
||||||
use Spatie\LaravelPackageTools\PackageServiceProvider;
|
use Spatie\LaravelPackageTools\PackageServiceProvider;
|
||||||
|
use Symfony\Component\HtmlSanitizer\HtmlSanitizer;
|
||||||
|
use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig;
|
||||||
|
|
||||||
class CommentsServiceProvider extends PackageServiceProvider
|
class CommentsServiceProvider extends PackageServiceProvider
|
||||||
{
|
{
|
||||||
@@ -49,6 +53,27 @@ class CommentsServiceProvider extends PackageServiceProvider
|
|||||||
MentionResolver::class,
|
MentionResolver::class,
|
||||||
fn () => new (CommentsConfig::getMentionResolver())
|
fn () => new (CommentsConfig::getMentionResolver())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$this->app->scoped(
|
||||||
|
'comments.html_sanitizer',
|
||||||
|
fn (): HtmlSanitizer => new HtmlSanitizer(
|
||||||
|
(new HtmlSanitizerConfig)
|
||||||
|
->allowSafeElements()
|
||||||
|
->allowRelativeLinks()
|
||||||
|
->allowRelativeMedias()
|
||||||
|
->allowAttribute('class', allowedElements: '*')
|
||||||
|
->allowAttribute('data-color', allowedElements: '*')
|
||||||
|
->allowAttribute('data-from-breakpoint', allowedElements: '*')
|
||||||
|
->allowAttribute('data-type', allowedElements: '*')
|
||||||
|
->allowAttribute('data-id', allowedElements: 'span')
|
||||||
|
->allowAttribute('data-label', allowedElements: 'span')
|
||||||
|
->allowAttribute('data-char', allowedElements: 'span')
|
||||||
|
->allowAttribute('style', allowedElements: '*')
|
||||||
|
->allowAttribute('width', allowedElements: 'img')
|
||||||
|
->allowAttribute('height', allowedElements: 'img')
|
||||||
|
->withMaxInputLength(500000)
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function packageBooted(): void
|
public function packageBooted(): void
|
||||||
@@ -64,5 +89,9 @@ class CommentsServiceProvider extends PackageServiceProvider
|
|||||||
Livewire::component('comments', Comments::class);
|
Livewire::component('comments', Comments::class);
|
||||||
Livewire::component('comment-item', CommentItem::class);
|
Livewire::component('comment-item', CommentItem::class);
|
||||||
Livewire::component('reactions', Reactions::class);
|
Livewire::component('reactions', Reactions::class);
|
||||||
|
|
||||||
|
FilamentAsset::register([
|
||||||
|
Css::make('comments', __DIR__.'/../resources/css/comments.css'),
|
||||||
|
], 'relaticle/comments');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ class CommentsAction extends Action
|
|||||||
$count = $record->commentCount();
|
$count = $record->commentCount();
|
||||||
|
|
||||||
return $count > 0 ? $count : null;
|
return $count > 0 ? $count : null;
|
||||||
});
|
})
|
||||||
|
->badgeColor('gray');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getDefaultName(): ?string
|
public static function getDefaultName(): ?string
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Relaticle\Comments\Livewire;
|
namespace Relaticle\Comments\Livewire;
|
||||||
|
|
||||||
|
use Filament\Actions\Concerns\InteractsWithActions;
|
||||||
|
use Filament\Actions\Contracts\HasActions;
|
||||||
use Filament\Forms\Components\RichEditor;
|
use Filament\Forms\Components\RichEditor;
|
||||||
use Filament\Forms\Concerns\InteractsWithForms;
|
use Filament\Forms\Concerns\InteractsWithForms;
|
||||||
use Filament\Forms\Contracts\HasForms;
|
use Filament\Forms\Contracts\HasForms;
|
||||||
@@ -17,8 +19,9 @@ use Relaticle\Comments\Events\CommentUpdated;
|
|||||||
use Relaticle\Comments\Mentions\MentionParser;
|
use Relaticle\Comments\Mentions\MentionParser;
|
||||||
use Relaticle\Comments\Models\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
|
|
||||||
class CommentItem extends Component implements HasForms
|
class CommentItem extends Component implements HasActions, HasForms
|
||||||
{
|
{
|
||||||
|
use InteractsWithActions;
|
||||||
use InteractsWithForms;
|
use InteractsWithForms;
|
||||||
use WithFileUploads;
|
use WithFileUploads;
|
||||||
|
|
||||||
@@ -180,6 +183,8 @@ class CommentItem extends Component implements HasForms
|
|||||||
|
|
||||||
app(MentionParser::class)->syncMentions($reply);
|
app(MentionParser::class)->syncMentions($reply);
|
||||||
|
|
||||||
|
$this->comment->load(['replies.commenter', 'replies.mentions', 'replies.attachments', 'replies.reactions.commenter', 'replies.replies.commenter', 'replies.replies.mentions', 'replies.replies.attachments', 'replies.replies.reactions.commenter']);
|
||||||
|
|
||||||
$this->dispatch('commentUpdated');
|
$this->dispatch('commentUpdated');
|
||||||
|
|
||||||
$this->isReplying = false;
|
$this->isReplying = false;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
namespace Relaticle\Comments\Livewire;
|
namespace Relaticle\Comments\Livewire;
|
||||||
|
|
||||||
|
use Filament\Actions\Concerns\InteractsWithActions;
|
||||||
|
use Filament\Actions\Contracts\HasActions;
|
||||||
use Filament\Forms\Components\RichEditor;
|
use Filament\Forms\Components\RichEditor;
|
||||||
use Filament\Forms\Concerns\InteractsWithForms;
|
use Filament\Forms\Concerns\InteractsWithForms;
|
||||||
use Filament\Forms\Contracts\HasForms;
|
use Filament\Forms\Contracts\HasForms;
|
||||||
@@ -19,8 +21,9 @@ use Relaticle\Comments\Mentions\MentionParser;
|
|||||||
use Relaticle\Comments\Models\Comment;
|
use Relaticle\Comments\Models\Comment;
|
||||||
use Relaticle\Comments\Models\Subscription;
|
use Relaticle\Comments\Models\Subscription;
|
||||||
|
|
||||||
class Comments extends Component implements HasForms
|
class Comments extends Component implements HasActions, HasForms
|
||||||
{
|
{
|
||||||
|
use InteractsWithActions;
|
||||||
use InteractsWithForms;
|
use InteractsWithForms;
|
||||||
use WithFileUploads;
|
use WithFileUploads;
|
||||||
|
|
||||||
@@ -68,7 +71,7 @@ class Comments extends Component implements HasForms
|
|||||||
{
|
{
|
||||||
return $this->model
|
return $this->model
|
||||||
->topLevelComments()
|
->topLevelComments()
|
||||||
->with(['commenter', 'mentions', 'attachments', 'reactions.commenter', 'replies.commenter', 'replies.mentions', 'replies.attachments', 'replies.reactions.commenter'])
|
->with(['commenter', 'mentions', 'attachments', 'reactions.commenter', 'replies.commenter', 'replies.mentions', 'replies.attachments', 'replies.reactions.commenter', 'replies.replies.commenter', 'replies.replies.mentions', 'replies.replies.attachments', 'replies.replies.reactions.commenter'])
|
||||||
->orderBy('created_at', $this->sortDirection)
|
->orderBy('created_at', $this->sortDirection)
|
||||||
->take($this->loadedCount)
|
->take($this->loadedCount)
|
||||||
->get();
|
->get();
|
||||||
@@ -80,6 +83,12 @@ class Comments extends Component implements HasForms
|
|||||||
return $this->model->topLevelComments()->count();
|
return $this->model->topLevelComments()->count();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Computed]
|
||||||
|
public function allCommentsCount(): int
|
||||||
|
{
|
||||||
|
return $this->model->commentCount();
|
||||||
|
}
|
||||||
|
|
||||||
#[Computed]
|
#[Computed]
|
||||||
public function hasMore(): bool
|
public function hasMore(): bool
|
||||||
{
|
{
|
||||||
@@ -203,7 +212,7 @@ class Comments extends Component implements HasForms
|
|||||||
|
|
||||||
public function refreshComments(): void
|
public function refreshComments(): void
|
||||||
{
|
{
|
||||||
unset($this->comments, $this->totalCount, $this->hasMore);
|
unset($this->comments, $this->totalCount, $this->hasMore, $this->allCommentsCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render(): View
|
public function render(): View
|
||||||
|
|||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
namespace Relaticle\Comments\Models;
|
namespace Relaticle\Comments\Models;
|
||||||
|
|
||||||
use Filament\Forms\Components\RichEditor\MentionProvider;
|
|
||||||
use Filament\Forms\Components\RichEditor\RichContentRenderer;
|
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
@@ -11,7 +9,6 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
|
|||||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Relaticle\Comments\CommentsConfig;
|
use Relaticle\Comments\CommentsConfig;
|
||||||
use Relaticle\Comments\Database\Factories\CommentFactory;
|
use Relaticle\Comments\Database\Factories\CommentFactory;
|
||||||
|
|
||||||
@@ -25,7 +22,11 @@ class Comment extends Model
|
|||||||
parent::boot();
|
parent::boot();
|
||||||
|
|
||||||
static::saving(function (self $comment): void {
|
static::saving(function (self $comment): void {
|
||||||
$comment->body = Str::sanitizeHtml($comment->body);
|
$comment->body = app('comments.html_sanitizer')->sanitize($comment->body);
|
||||||
|
});
|
||||||
|
|
||||||
|
static::deleting(function (self $comment): void {
|
||||||
|
$comment->replies()->each(fn ($reply) => $reply->delete());
|
||||||
});
|
});
|
||||||
|
|
||||||
static::forceDeleting(function (self $comment): void {
|
static::forceDeleting(function (self $comment): void {
|
||||||
@@ -145,33 +146,23 @@ class Comment extends Model
|
|||||||
{
|
{
|
||||||
$body = $this->body;
|
$body = $this->body;
|
||||||
|
|
||||||
if ($this->hasRichEditorMentions($body)) {
|
|
||||||
return RichContentRenderer::make($body)
|
|
||||||
->mentions([
|
|
||||||
MentionProvider::make('@')
|
|
||||||
->getLabelsUsing(fn (array $ids): array => CommentsConfig::getCommenterModel()::query()
|
|
||||||
->whereIn('id', $ids)
|
|
||||||
->pluck('name', 'id')
|
|
||||||
->all()),
|
|
||||||
])
|
|
||||||
->toHtml();
|
|
||||||
}
|
|
||||||
|
|
||||||
$mentionNames = $this->mentions->pluck('name')->filter()->unique();
|
$mentionNames = $this->mentions->pluck('name')->filter()->unique();
|
||||||
|
|
||||||
foreach ($mentionNames as $name) {
|
foreach ($mentionNames as $name) {
|
||||||
$escapedName = e($name);
|
$escapedName = e($name);
|
||||||
$styledSpan = '<span class="comment-mention inline rounded bg-primary-50 px-1 font-medium text-primary-700 dark:bg-primary-900/30 dark:text-primary-300">@'.$escapedName.'</span>';
|
$styledSpan = '<span class="comment-mention">@'.$escapedName.'</span>';
|
||||||
|
|
||||||
$body = str_replace("@{$name}", $styledSpan, $body);
|
$pattern = '/<(?:span|a)[^>]*data-type="mention"[^>]*>@?'.preg_quote($escapedName, '/').'<\/(?:span|a)>/';
|
||||||
$body = str_replace("@{$name}", $styledSpan, $body);
|
|
||||||
|
if (preg_match($pattern, $body)) {
|
||||||
|
$body = preg_replace($pattern, $styledSpan, $body);
|
||||||
|
} else {
|
||||||
|
// Fallback for plain-text mentions
|
||||||
|
$body = str_replace("@{$name}", $styledSpan, $body);
|
||||||
|
$body = str_replace("@{$name}", $styledSpan, $body);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $body;
|
return $body;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function hasRichEditorMentions(string $body): bool
|
|
||||||
{
|
|
||||||
return str_contains($body, 'data-type="mention"') || str_contains($body, '<p>') || str_contains($body, '<br');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -155,6 +155,26 @@ it('strips onclick handler from elements', function () {
|
|||||||
expect($comment->body)->toContain('click me');
|
expect($comment->body)->toContain('click me');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('preserves mention data attributes in comment body', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
|
$body = '<span data-type="mention" data-id="1" data-label="max" data-char="@">@max</span>';
|
||||||
|
|
||||||
|
$comment = Comment::factory()->create([
|
||||||
|
'commentable_id' => $post->id,
|
||||||
|
'commentable_type' => $post->getMorphClass(),
|
||||||
|
'commenter_id' => $user->getKey(),
|
||||||
|
'commenter_type' => $user->getMorphClass(),
|
||||||
|
'body' => $body,
|
||||||
|
]);
|
||||||
|
|
||||||
|
expect($comment->body)->toContain('data-type="mention"');
|
||||||
|
expect($comment->body)->toContain('data-id="1"');
|
||||||
|
expect($comment->body)->toContain('data-label="max"');
|
||||||
|
expect($comment->body)->toContain('data-char="@"');
|
||||||
|
});
|
||||||
|
|
||||||
it('sanitizes content submitted through livewire component', function () {
|
it('sanitizes content submitted through livewire component', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|||||||
@@ -51,6 +51,28 @@ it('renders multiple mentions with styled spans', function () {
|
|||||||
expect($rendered)->toContain('comment-mention');
|
expect($rendered)->toContain('comment-mention');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('renders rich-editor mention span as styled mention', function () {
|
||||||
|
$user = User::factory()->create();
|
||||||
|
$alice = User::factory()->create(['name' => 'Alice']);
|
||||||
|
$post = Post::factory()->create();
|
||||||
|
|
||||||
|
$comment = Comment::factory()->create([
|
||||||
|
'commentable_id' => $post->id,
|
||||||
|
'commentable_type' => $post->getMorphClass(),
|
||||||
|
'commenter_id' => $user->getKey(),
|
||||||
|
'commenter_type' => $user->getMorphClass(),
|
||||||
|
'body' => '<p><span data-type="mention" data-id="'.$alice->id.'" data-label="Alice" data-char="@">@Alice</span> said hi</p>',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$comment->mentions()->attach($alice->id, ['commenter_type' => $alice->getMorphClass()]);
|
||||||
|
|
||||||
|
$rendered = $comment->renderBodyWithMentions();
|
||||||
|
|
||||||
|
expect($rendered)->toContain('comment-mention');
|
||||||
|
expect($rendered)->toContain('@Alice</span>');
|
||||||
|
expect($rendered)->not->toContain('data-type="mention"');
|
||||||
|
});
|
||||||
|
|
||||||
it('does not style non-mentioned @text', function () {
|
it('does not style non-mentioned @text', function () {
|
||||||
$user = User::factory()->create();
|
$user = User::factory()->create();
|
||||||
$post = Post::factory()->create();
|
$post = Post::factory()->create();
|
||||||
|
|||||||
@@ -10,6 +10,17 @@ use Relaticle\Comments\Models\Comment;
|
|||||||
use Relaticle\Comments\Tests\Models\Post;
|
use Relaticle\Comments\Tests\Models\Post;
|
||||||
use Relaticle\Comments\Tests\Models\User;
|
use Relaticle\Comments\Tests\Models\User;
|
||||||
|
|
||||||
|
it('parses rich-editor mention spans using data-id', function () {
|
||||||
|
$john = User::factory()->create(['name' => 'john']);
|
||||||
|
|
||||||
|
$parser = app(MentionParser::class);
|
||||||
|
$body = '<p>Hello <span data-type="mention" data-id="'.$john->id.'" data-label="john" data-char="@">@john</span></p>';
|
||||||
|
$result = $parser->parse($body);
|
||||||
|
|
||||||
|
expect($result)->toHaveCount(1);
|
||||||
|
expect($result->first())->toBe($john->id);
|
||||||
|
});
|
||||||
|
|
||||||
it('parses @username from plain text body', function () {
|
it('parses @username from plain text body', function () {
|
||||||
User::factory()->create(['name' => 'john']);
|
User::factory()->create(['name' => 'john']);
|
||||||
User::factory()->create(['name' => 'jane']);
|
User::factory()->create(['name' => 'jane']);
|
||||||
|
|||||||
Reference in New Issue
Block a user