mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-26 08:13:16 +00:00
Merge pull request #1310 from pixelfed/frontend-ui-refactor
Frontend ui refactor
This commit is contained in:
commit
1e86169b79
11 changed files with 149 additions and 50 deletions
|
@ -2,16 +2,18 @@
|
||||||
|
|
||||||
namespace App\Jobs\CommentPipeline;
|
namespace App\Jobs\CommentPipeline;
|
||||||
|
|
||||||
use App\Notification;
|
use App\{
|
||||||
use App\Status;
|
Notification,
|
||||||
use Cache;
|
Status
|
||||||
|
};
|
||||||
|
use App\Services\NotificationService;
|
||||||
|
use DB, Cache, Log, Redis;
|
||||||
|
|
||||||
use Illuminate\Bus\Queueable;
|
use Illuminate\Bus\Queueable;
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||||
use Illuminate\Foundation\Bus\Dispatchable;
|
use Illuminate\Foundation\Bus\Dispatchable;
|
||||||
use Illuminate\Queue\InteractsWithQueue;
|
use Illuminate\Queue\InteractsWithQueue;
|
||||||
use Illuminate\Queue\SerializesModels;
|
use Illuminate\Queue\SerializesModels;
|
||||||
use Log;
|
|
||||||
use Redis;
|
|
||||||
|
|
||||||
class CommentPipeline implements ShouldQueue
|
class CommentPipeline implements ShouldQueue
|
||||||
{
|
{
|
||||||
|
@ -55,7 +57,7 @@ class CommentPipeline implements ShouldQueue
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
DB::transaction(function() use($target, $actor, $comment) {
|
||||||
$notification = new Notification();
|
$notification = new Notification();
|
||||||
$notification->profile_id = $target->id;
|
$notification->profile_id = $target->id;
|
||||||
$notification->actor_id = $actor->id;
|
$notification->actor_id = $actor->id;
|
||||||
|
@ -66,14 +68,8 @@ class CommentPipeline implements ShouldQueue
|
||||||
$notification->item_type = "App\Status";
|
$notification->item_type = "App\Status";
|
||||||
$notification->save();
|
$notification->save();
|
||||||
|
|
||||||
Cache::forever('notification.'.$notification->id, $notification);
|
NotificationService::setNotification($notification);
|
||||||
|
NotificationService::set($notification->profile_id, $notification->id);
|
||||||
$redis = Redis::connection();
|
});
|
||||||
|
|
||||||
$nkey = config('cache.prefix').':user.'.$target->id.'.notifications';
|
|
||||||
$redis->lpush($nkey, $notification->id);
|
|
||||||
} catch (Exception $e) {
|
|
||||||
Log::error($e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
namespace App\Jobs\StatusPipeline;
|
namespace App\Jobs\StatusPipeline;
|
||||||
|
|
||||||
|
use DB;
|
||||||
use App\{
|
use App\{
|
||||||
Notification,
|
Notification,
|
||||||
Report,
|
Report,
|
||||||
|
@ -79,6 +80,14 @@ class StatusDelete implements ShouldQueue
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if($status->in_reply_to_id) {
|
||||||
|
DB::transaction(function() use($status) {
|
||||||
|
$parent = Status::findOrFail($status->in_reply_to_id);
|
||||||
|
--$parent->reply_count;
|
||||||
|
$parent->save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
DB::transaction(function() use($status) {
|
||||||
$comments = Status::where('in_reply_to_id', $status->id)->get();
|
$comments = Status::where('in_reply_to_id', $status->id)->get();
|
||||||
foreach ($comments as $comment) {
|
foreach ($comments as $comment) {
|
||||||
$comment->in_reply_to_id = null;
|
$comment->in_reply_to_id = null;
|
||||||
|
@ -87,7 +96,6 @@ class StatusDelete implements ShouldQueue
|
||||||
->whereItemId($comment->id)
|
->whereItemId($comment->id)
|
||||||
->delete();
|
->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
$status->likes()->delete();
|
$status->likes()->delete();
|
||||||
Notification::whereItemType('App\Status')
|
Notification::whereItemType('App\Status')
|
||||||
->whereItemId($status->id)
|
->whereItemId($status->id)
|
||||||
|
@ -97,6 +105,7 @@ class StatusDelete implements ShouldQueue
|
||||||
->whereObjectId($status->id)
|
->whereObjectId($status->id)
|
||||||
->delete();
|
->delete();
|
||||||
$status->delete();
|
$status->delete();
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ class StatusEntityLexer implements ShouldQueue
|
||||||
$status = $this->status;
|
$status = $this->status;
|
||||||
|
|
||||||
foreach ($mentions as $mention) {
|
foreach ($mentions as $mention) {
|
||||||
$mentioned = Profile::whereUsername($mention)->firstOrFail();
|
$mentioned = Profile::whereNull('domain')->whereUsername($mention)->firstOrFail();
|
||||||
|
|
||||||
if (empty($mentioned) || !isset($mentioned->id)) {
|
if (empty($mentioned) || !isset($mentioned->id)) {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -81,6 +81,16 @@ class NotificationService {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function setNotification(Notification $notification)
|
||||||
|
{
|
||||||
|
return Cache::remember('service:notification:'.$notification->id, now()->addDays(7), function() use($notification) {
|
||||||
|
$fractal = new Fractal\Manager();
|
||||||
|
$fractal->setSerializer(new ArraySerializer());
|
||||||
|
$resource = new Fractal\Resource\Item($notification, new NotificationTransformer());
|
||||||
|
return $fractal->createData($resource)->toArray();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public static function warmCache($id, $stop = 100, $force = false)
|
public static function warmCache($id, $stop = 100, $force = false)
|
||||||
{
|
{
|
||||||
if(self::count($id) == 0 || $force == true) {
|
if(self::count($id) == 0 || $force == true) {
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
namespace App\Util\Lexer;
|
namespace App\Util\Lexer;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Twitter Autolink Class.
|
* Twitter Autolink Class.
|
||||||
*
|
*
|
||||||
|
@ -413,7 +415,11 @@ class Autolink extends Regex
|
||||||
$beginIndex = 0;
|
$beginIndex = 0;
|
||||||
foreach ($entities as $entity) {
|
foreach ($entities as $entity) {
|
||||||
if (isset($entity['screen_name'])) {
|
if (isset($entity['screen_name'])) {
|
||||||
|
if(Str::startsWith($entity['screen_name'], '@')) {
|
||||||
|
$text .= StringUtils::substr($tweet, $beginIndex, $entity['indices'][0] - $beginIndex);
|
||||||
|
} else {
|
||||||
$text .= StringUtils::substr($tweet, $beginIndex, $entity['indices'][0] - $beginIndex + 1);
|
$text .= StringUtils::substr($tweet, $beginIndex, $entity['indices'][0] - $beginIndex + 1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$text .= StringUtils::substr($tweet, $beginIndex, $entity['indices'][0] - $beginIndex);
|
$text .= StringUtils::substr($tweet, $beginIndex, $entity['indices'][0] - $beginIndex);
|
||||||
}
|
}
|
||||||
|
@ -704,7 +710,7 @@ class Autolink extends Regex
|
||||||
|
|
||||||
if (!empty($entity['list_slug'])) {
|
if (!empty($entity['list_slug'])) {
|
||||||
// Replace the list and username
|
// Replace the list and username
|
||||||
$linkText = $entity['screen_name'].$entity['list_slug'];
|
$linkText = $entity['screen_name'];
|
||||||
$class = $this->class_list;
|
$class = $this->class_list;
|
||||||
$url = $this->url_base_list.$linkText;
|
$url = $this->url_base_list.$linkText;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
namespace App\Util\Lexer;
|
namespace App\Util\Lexer;
|
||||||
|
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Twitter Extractor Class.
|
* Twitter Extractor Class.
|
||||||
*
|
*
|
||||||
|
@ -452,8 +454,9 @@ class Extractor extends Regex
|
||||||
list($all, $before, $at, $username, $list_slug, $outer) = array_pad($match, 6, ['', 0]);
|
list($all, $before, $at, $username, $list_slug, $outer) = array_pad($match, 6, ['', 0]);
|
||||||
$start_position = $at[1] > 0 ? StringUtils::strlen(substr($tweet, 0, $at[1])) : $at[1];
|
$start_position = $at[1] > 0 ? StringUtils::strlen(substr($tweet, 0, $at[1])) : $at[1];
|
||||||
$end_position = $start_position + StringUtils::strlen($at[0]) + StringUtils::strlen($username[0]);
|
$end_position = $start_position + StringUtils::strlen($at[0]) + StringUtils::strlen($username[0]);
|
||||||
|
$screenname = trim($all[0]) == '@'.$username[0] ? $username[0] : trim($all[0]);
|
||||||
$entity = [
|
$entity = [
|
||||||
'screen_name' => $username[0],
|
'screen_name' => $screenname,
|
||||||
'list_slug' => $list_slug[0],
|
'list_slug' => $list_slug[0],
|
||||||
'indices' => [$start_position, $end_position],
|
'indices' => [$start_position, $end_position],
|
||||||
];
|
];
|
||||||
|
|
|
@ -161,7 +161,9 @@ abstract class Regex
|
||||||
// $after in the following regular expression. Note that we only use a
|
// $after in the following regular expression. Note that we only use a
|
||||||
// look-ahead capture here and don't append $after when we return.
|
// look-ahead capture here and don't append $after when we return.
|
||||||
$tmp['valid_mention_preceding_chars'] = '([^a-zA-Z0-9_!#\$%&*@@\/]|^|(?:^|[^a-z0-9_+~.-])RT:?)';
|
$tmp['valid_mention_preceding_chars'] = '([^a-zA-Z0-9_!#\$%&*@@\/]|^|(?:^|[^a-z0-9_+~.-])RT:?)';
|
||||||
$re['valid_mentions_or_lists'] = '/'.$tmp['valid_mention_preceding_chars'].'(['.$tmp['at_signs'].'])([a-z0-9_]{1,20})(\/[a-z][a-z0-9_\-]{0,24})?(?=(.*|$))/iu';
|
|
||||||
|
$re['valid_mentions_or_lists'] = '/'.$tmp['valid_mention_preceding_chars'].'(['.$tmp['at_signs'].'])([a-z0-9_]{1,20})((\/[a-z][a-z0-9_\-]{0,24})?(?=(.*|$))(?:@[a-z0-9\.\-]+[a-z0-9]+)?)/i';
|
||||||
|
|
||||||
$re['valid_reply'] = '/^(?:['.$tmp['spaces'].'])*['.$tmp['at_signs'].']([a-z0-9_]{1,20})(?=(.*|$))/iu';
|
$re['valid_reply'] = '/^(?:['.$tmp['spaces'].'])*['.$tmp['at_signs'].']([a-z0-9_]{1,20})(?=(.*|$))/iu';
|
||||||
$re['end_mention_match'] = '/\A(?:['.$tmp['at_signs'].']|['.$tmp['latin_accents'].']|:\/\/)/iu';
|
$re['end_mention_match'] = '/\A(?:['.$tmp['at_signs'].']|['.$tmp['latin_accents'].']|:\/\/)/iu';
|
||||||
|
|
||||||
|
|
BIN
public/js/status.js
vendored
BIN
public/js/status.js
vendored
Binary file not shown.
Binary file not shown.
|
@ -107,7 +107,7 @@
|
||||||
<div class="d-flex flex-md-column flex-column-reverse h-100">
|
<div class="d-flex flex-md-column flex-column-reverse h-100">
|
||||||
<div class="card-body status-comments pb-5">
|
<div class="card-body status-comments pb-5">
|
||||||
<div class="status-comment">
|
<div class="status-comment">
|
||||||
<p class="mb-1 read-more" style="overflow: hidden;">
|
<p :class="[status.content.length > 420 ? 'mb-1 read-more' : 'mb-1']" style="overflow: hidden;">
|
||||||
<span class="font-weight-bold pr-1">{{statusUsername}}</span>
|
<span class="font-weight-bold pr-1">{{statusUsername}}</span>
|
||||||
<span class="comment-text" :id="status.id + '-status-readmore'" v-html="status.content"></span>
|
<span class="comment-text" :id="status.id + '-status-readmore'" v-html="status.content"></span>
|
||||||
</p>
|
</p>
|
||||||
|
@ -120,8 +120,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="postCommentsContainer d-none pt-3">
|
<div class="postCommentsContainer d-none pt-3">
|
||||||
<p v-if="status.reply_count > 10"class="mb-1 text-center load-more-link d-none"><a href="#" class="text-muted" v-on:click="loadMore">Load more comments</a></p>
|
<p v-if="status.reply_count > 10"class="mb-1 text-center load-more-link d-none"><a href="#" class="text-muted" v-on:click="loadMore">Load more comments</a></p>
|
||||||
<div class="comments" data-min-id="0" data-max-id="0">
|
<div class="comments">
|
||||||
<div v-for="(reply, index) in results" class="pb-3">
|
<div v-for="(reply, index) in results" class="pb-3" :key="'tl' + reply.id + '_' + index">
|
||||||
<p class="d-flex justify-content-between align-items-top read-more" style="overflow-y: hidden;">
|
<p class="d-flex justify-content-between align-items-top read-more" style="overflow-y: hidden;">
|
||||||
<span>
|
<span>
|
||||||
<a class="text-dark font-weight-bold mr-1" :href="reply.account.url" v-bind:title="reply.account.username">{{truncate(reply.account.username,15)}}</a>
|
<a class="text-dark font-weight-bold mr-1" :href="reply.account.url" v-bind:title="reply.account.username">{{truncate(reply.account.username,15)}}</a>
|
||||||
|
@ -133,21 +133,32 @@
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
<p class="">
|
<p class="">
|
||||||
<span class="text-muted mr-3" style="width: 20px;" v-text="timeAgo(reply.created_at)"></span>
|
<a v-once class="text-muted mr-3 text-decoration-none small" style="width: 20px;" v-text="timeAgo(reply.created_at)" :href="reply.url"></a>
|
||||||
<span v-if="reply.favourites_count" class="text-muted comment-reaction font-weight-bold mr-3">{{reply.favourites_count == 1 ? '1 like' : reply.favourites_count + ' likes'}}</span>
|
<span v-if="reply.favourites_count" class="text-muted comment-reaction font-weight-bold mr-3">{{reply.favourites_count == 1 ? '1 like' : reply.favourites_count + ' likes'}}</span>
|
||||||
<span class="text-muted comment-reaction font-weight-bold cursor-pointer" v-on:click="replyFocus(reply)">Reply</span>
|
<span class="text-muted comment-reaction font-weight-bold cursor-pointer" v-on:click="replyFocus(reply, index)">Reply</span>
|
||||||
</p>
|
</p>
|
||||||
<div v-if="reply.reply_count > 0" class="cursor-pointer" style="margin-left:30px;" v-on:click="toggleReplies(reply)">
|
<div v-if="reply.reply_count > 0" class="cursor-pointer" style="margin-left:30px;" v-on:click="toggleReplies(reply)">
|
||||||
<span class="show-reply-bar"></span>
|
<span class="show-reply-bar"></span>
|
||||||
<span class="comment-reaction font-weight-bold text-muted">{{reply.thread ? 'Hide' : 'View'}} Replies ({{reply.reply_count}})</span>
|
<span class="comment-reaction font-weight-bold text-muted">{{reply.thread ? 'Hide' : 'View'}} Replies ({{reply.reply_count}})</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="reply.thread == true" class="comment-thread">
|
<div v-if="reply.thread == true" class="comment-thread">
|
||||||
<p class="d-flex justify-content-between align-items-top read-more pb-3" style="overflow-y: hidden;" v-for="(s, index) in reply.replies">
|
<div v-for="(s, sindex) in reply.replies" class="pb-3" :key="'cr' + s.id + '_' + index">
|
||||||
|
<p class="d-flex justify-content-between align-items-top read-more" style="overflow-y: hidden;">
|
||||||
<span>
|
<span>
|
||||||
<a class="text-dark font-weight-bold mr-1" :href="s.account.url" :title="s.account.username">{{s.account.username}}</a>
|
<a class="text-dark font-weight-bold mr-1" :href="s.account.url" :title="s.account.username">{{s.account.username}}</a>
|
||||||
<span class="text-break" v-html="s.content"></span>
|
<span class="text-break" v-html="s.content"></span>
|
||||||
</span>
|
</span>
|
||||||
|
<span class="pl-2" style="min-width:38px">
|
||||||
|
<span v-on:click="likeReply(s, $event)"><i v-bind:class="[s.favourited ? 'fas fa-heart fa-sm text-danger':'far fa-heart fa-sm text-lighter']"></i></span>
|
||||||
|
<post-menu :status="s" :profile="user" :size="'sm'" :modal="'true'" class="d-inline-block pl-2" v-on:deletePost="deleteCommentReply(s.id, sindex, index) "></post-menu>
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
|
<p class="">
|
||||||
|
<a v-once class="text-muted mr-3 text-decoration-none small" style="width: 20px;" v-text="timeAgo(s.created_at)" :href="s.url"></a>
|
||||||
|
<span v-if="s.favourites_count" class="text-muted comment-reaction font-weight-bold mr-3">{{s.favourites_count == 1 ? '1 like' : s.favourites_count + ' likes'}}</span>
|
||||||
|
<span class="text-muted comment-reaction font-weight-bold cursor-pointer" v-on:click="replyFocus(s, sindex)">Reply</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -473,6 +484,7 @@ export default {
|
||||||
loaded: false,
|
loaded: false,
|
||||||
loading: null,
|
loading: null,
|
||||||
replyingToId: this.statusId,
|
replyingToId: this.statusId,
|
||||||
|
replyToIndex: 0,
|
||||||
emoji: ['😀','😁','😂','🤣','😃','😄','😅','😆','😉','😊','😋','😎','😍','😘','😗','😙','😚','☺️','🙂','🤗','🤩','🤔','🤨','😐','😑','😶','🙄','😏','😣','😥','😮','🤐','😯','😪','😫','😴','😌','😛','😜','😝','🤤','😒','😓','😔','😕','🙃','🤑','😲','☹️','🙁','😖','😞','😟','😤','😢','😭','😦','😧','😨','😩','🤯','😬','😰','😱','😳','🤪','😵','😡','😠','🤬','😷','🤒','🤕','🤢','🤮','🤧','😇','🤠','🤡','🤥','🤫','🤭','🧐','🤓','😈','👿','👹','👺','💀','👻','👽','🤖','💩','😺','😸','😹','😻','😼','😽','🙀','😿','😾','🤲','👐','🙌','👏','🤝','👍','👎','👊','✊','🤛','🤜','🤞','✌️','🤟','🤘','👌','👈','👉','👆','👇','☝️','✋','🤚','🖐','🖖','👋','🤙','💪','🖕','✍️','🙏','💍','💄','💋','👄','👅','👂','👃','👣','👁','👀','🧠','🗣','👤','👥'],
|
emoji: ['😀','😁','😂','🤣','😃','😄','😅','😆','😉','😊','😋','😎','😍','😘','😗','😙','😚','☺️','🙂','🤗','🤩','🤔','🤨','😐','😑','😶','🙄','😏','😣','😥','😮','🤐','😯','😪','😫','😴','😌','😛','😜','😝','🤤','😒','😓','😔','😕','🙃','🤑','😲','☹️','🙁','😖','😞','😟','😤','😢','😭','😦','😧','😨','😩','🤯','😬','😰','😱','😳','🤪','😵','😡','😠','🤬','😷','🤒','🤕','🤢','🤮','🤧','😇','🤠','🤡','🤥','🤫','🤭','🧐','🤓','😈','👿','👹','👺','💀','👻','👽','🤖','💩','😺','😸','😹','😻','😼','😽','🙀','😿','😾','🤲','👐','🙌','👏','🤝','👍','👎','👊','✊','🤛','🤜','🤞','✌️','🤟','🤘','👌','👈','👉','👆','👇','☝️','✋','🤚','🖐','🖖','👋','🤙','💪','🖕','✍️','🙏','💍','💄','💋','👄','👅','👂','👃','👣','👁','👀','🧠','🗣','👤','👥'],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -750,7 +762,11 @@ export default {
|
||||||
let elem = $('.status-comments')[0];
|
let elem = $('.status-comments')[0];
|
||||||
elem.scrollTop = elem.clientHeight;
|
elem.scrollTop = elem.clientHeight;
|
||||||
} else {
|
} else {
|
||||||
|
if(self.replyToIndex >= 0) {
|
||||||
|
let el = self.results[self.replyToIndex];
|
||||||
|
el.replies.push(entity);
|
||||||
|
el.reply_count = el.reply_count + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
self.replyText = '';
|
self.replyText = '';
|
||||||
});
|
});
|
||||||
|
@ -767,13 +783,26 @@ export default {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
deleteCommentReply(id, i, pi) {
|
||||||
|
axios.post('/i/delete', {
|
||||||
|
type: 'comment',
|
||||||
|
item: id
|
||||||
|
}).then(res => {
|
||||||
|
this.results[pi].replies.splice(i, 1);
|
||||||
|
--this.results[pi].reply_count;
|
||||||
|
}).catch(err => {
|
||||||
|
swal('Something went wrong!', 'Please try again later', 'error');
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
l(e) {
|
l(e) {
|
||||||
let len = e.length;
|
let len = e.length;
|
||||||
if(len < 10) { return e; }
|
if(len < 10) { return e; }
|
||||||
return e.substr(0, 10)+'...';
|
return e.substr(0, 10)+'...';
|
||||||
},
|
},
|
||||||
|
|
||||||
replyFocus(e) {
|
replyFocus(e, index) {
|
||||||
|
this.replyToIndex = index;
|
||||||
this.replyingToId = e.id;
|
this.replyingToId = e.id;
|
||||||
this.reply_to_profile_id = e.account.id;
|
this.reply_to_profile_id = e.account.id;
|
||||||
this.replyText = '@' + e.account.username + ' ';
|
this.replyText = '@' + e.account.username + ' ';
|
||||||
|
|
|
@ -62,4 +62,48 @@ class StatusLexerTest extends TestCase
|
||||||
$expected = '@<a class="u-url mention" href="https://pixelfed.dev/pixelfed" rel="external nofollow noopener" target="_blank">pixelfed</a> hi, really like the website! <a href="https://pixelfed.dev/discover/tags/píxelfed?src=hash" title="#píxelfed" class="u-url hashtag" rel="external nofollow noopener">#píxelfed</a>';
|
$expected = '@<a class="u-url mention" href="https://pixelfed.dev/pixelfed" rel="external nofollow noopener" target="_blank">pixelfed</a> hi, really like the website! <a href="https://pixelfed.dev/discover/tags/píxelfed?src=hash" title="#píxelfed" class="u-url hashtag" rel="external nofollow noopener">#píxelfed</a>';
|
||||||
$this->assertEquals($this->autolink, $expected);
|
$this->assertEquals($this->autolink, $expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @test **/
|
||||||
|
public function remoteMention()
|
||||||
|
{
|
||||||
|
$expected = [
|
||||||
|
"hashtags" => [
|
||||||
|
"dansup",
|
||||||
|
],
|
||||||
|
"urls" => [],
|
||||||
|
"mentions" => [
|
||||||
|
"@dansup@mstdn.io",
|
||||||
|
"test",
|
||||||
|
],
|
||||||
|
"replyto" => null,
|
||||||
|
"hashtags_with_indices" => [
|
||||||
|
[
|
||||||
|
"hashtag" => "dansup",
|
||||||
|
"indices" => [
|
||||||
|
0,
|
||||||
|
7,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"urls_with_indices" => [],
|
||||||
|
"mentions_with_indices" => [
|
||||||
|
[
|
||||||
|
"screen_name" => "@dansup@mstdn.io",
|
||||||
|
"indices" => [
|
||||||
|
8,
|
||||||
|
24,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"screen_name" => "test",
|
||||||
|
"indices" => [
|
||||||
|
25,
|
||||||
|
30,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
$actual = Extractor::create()->extract('#dansup @dansup@mstdn.io @test');
|
||||||
|
$this->assertEquals($actual, $expected);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue