Compare commits

...

13 commits

Author SHA1 Message Date
Hypolite Petovan
a0f6f2e73e
Merge pull request #13752 from annando/capabilities
Store Pixelfed's capabilities
2023-12-21 11:20:36 -05:00
Hypolite Petovan
bb2eda5c28
Merge pull request #13753 from Raroun/fix_for_Issue_#13748_frio]_Increase_spacing_between_icon_and_text_in_More_menu
[frio] fix for Issue #13748
2023-12-21 07:46:41 -05:00
Michael
d1a28b4c20 Merge remote-tracking branch 'upstream/2023.09-rc' into capabilities 2023-12-21 10:41:58 +00:00
Michael
b4a380e9de Handle "commentsEnabled" 2023-12-21 10:26:34 +00:00
Raroun
d7c757d63e
Update wall_thread.tpl
Addes a bit more space between the icons and the text in the more menu on dektop and mobile
2023-12-21 08:06:59 +01:00
Michael
1b13c76d2e Simplyfied code 2023-12-21 05:01:24 +00:00
Hypolite Petovan
1cc76937d7
Merge pull request #13751 from annando/fix-capitalisation
Fix class name capitalisation
2023-12-20 19:48:06 -05:00
Michael
da65f0bea7 Store Pixelfed's capabilities 2023-12-21 00:33:42 +00:00
Michael
a86cd93fb8 Fix class name capitalisation 2023-12-20 19:55:34 +00:00
Michael Vogel
e15e17732d
Merge pull request #13749 from MrPetovan/bug/fatal-errors
Also catch TypeError exceptions in Repository\PostMedia
2023-12-20 19:09:08 +01:00
Hypolite Petovan
9024fc1226 Also catch TypeError exceptions in Repository\PostMedia
- Address "Uncaught Exception TypeError: "Friendica\Content\Post\Entity\PostMedia::__construct(): Argument #2 ($url) must be of type Psr\Http\Message\UriInterface, null given"
2023-12-20 09:50:49 -05:00
Hypolite Petovan
8fbcdd371e
Merge pull request #13742 from annando/edit-tags
Fix lost local tags upon update
2023-12-20 08:38:08 -05:00
Michael
fbcfa46beb Fix lost local tags upon update 2023-12-19 15:28:20 +00:00
8 changed files with 121 additions and 55 deletions

View file

@ -47,7 +47,7 @@ class PostMedia extends BaseRepository
foreach ($rows as $fields) {
try {
$Entities[] = $this->factory->createFromTableRow($fields);
} catch (\Exception $e) {
} catch (\Throwable $e) {
$this->logger->warning('Invalid media row', ['code' => $e->getCode(), 'message' => $e->getMessage(), 'fields' => $fields]);
}
}

View file

@ -196,6 +196,10 @@ class Item
$previous = Post::selectFirst(['edited'], $condition);
}
if (!empty($fields['body'])) {
$fields['body'] = self::setHashtags($fields['body']);
}
$rows = Post::update($fields, $condition);
if (is_bool($rows)) {
return $rows;

View file

@ -605,7 +605,7 @@ class UserNotification
if (empty($item['quote-uri-id']) || ($item['quote-uri-id'] == $item['uri-id'])) {
return false;
}
$condition = ['uri-id' => $item['quote-uri-id'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => [item::GRAVITY_PARENT, Item::GRAVITY_COMMENT]];
$condition = ['uri-id' => $item['quote-uri-id'], 'uid' => $item['uid'], 'author-id' => $contacts, 'deleted' => false, 'gravity' => [Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT]];
return Post::exists($condition);
}

View file

@ -60,6 +60,10 @@ class Tag
const AUDIENCE = 14;
const ATTRIBUTED = 15;
const CAN_ANNOUNCE = 20;
const CAN_LIKE = 21;
const CAN_REPLY = 22;
const ACCOUNT = 1;
const GENERAL_COLLECTION = 2;
const FOLLOWER_COLLECTION = 3;
@ -338,7 +342,7 @@ class Tag
/**
* Store raw tags (not encapsulated in links) from the body
* This function is needed in the intermediate phase.
* Later we can call item::setHashtags in advance to have all tags converted.
* Later we can call Item::setHashtags in advance to have all tags converted.
*
* @param integer $uriId URI-Id
* @param string $body Body of the post

View file

@ -918,6 +918,16 @@ class Processor
self::storeReceivers($item['uri-id'], $activity['receiver_urls'] ?? []);
if (!empty($activity['capabilities'])) {
$restrictions = self::storeCapabilities($item['uri-id'], $activity['capabilities']);
} elseif (!is_null($activity['can-comment']) && !$activity['can-comment']) {
$restrictions = [Tag::CAN_REPLY];
} else {
$restrictions = [];
}
// @todo Store restrictions
$item['location'] = $activity['location'];
if (!empty($activity['latitude']) && !empty($activity['longitude'])) {
@ -1118,7 +1128,7 @@ class Processor
continue;
}
if (($receiver != 0) && ($item['gravity'] == Item::GRAVITY_PARENT) && !in_array($item['post-reason'], [Item::PR_FOLLOWER, Item::PR_TAG, item::PR_TO, Item::PR_CC, Item::PR_AUDIENCE])) {
if (($receiver != 0) && ($item['gravity'] == Item::GRAVITY_PARENT) && !in_array($item['post-reason'], [Item::PR_FOLLOWER, Item::PR_TAG, Item::PR_TO, Item::PR_CC, Item::PR_AUDIENCE])) {
if (!$item['isGroup']) {
if ($item['post-reason'] == Item::PR_BCC) {
Logger::info('Top level post via BCC from a non sharer, ignoring', ['uid' => $receiver, 'contact' => $item['contact-id'], 'url' => $item['uri']]);
@ -1322,27 +1332,53 @@ class Processor
public static function storeReceivers(int $uriid, array $receivers)
{
foreach (['as:to' => Tag::TO, 'as:cc' => Tag::CC, 'as:bto' => Tag::BTO, 'as:bcc' => Tag::BCC, 'as:audience' => Tag::AUDIENCE, 'as:attributedTo' => Tag::ATTRIBUTED] as $element => $type) {
if (!empty($receivers[$element])) {
foreach ($receivers[$element] as $receiver) {
if ($receiver == ActivityPub::PUBLIC_COLLECTION) {
$name = Receiver::PUBLIC_COLLECTION;
} elseif ($path = parse_url($receiver, PHP_URL_PATH)) {
$name = trim($path, '/');
} elseif ($host = parse_url($receiver, PHP_URL_HOST)) {
$name = $host;
} else {
Logger::warning('Unable to coerce name from receiver', ['element' => $element, 'type' => $type, 'receiver' => $receiver]);
$name = '';
}
$target = Tag::getTargetType($receiver);
Logger::debug('Got target type', ['type' => $target, 'url' => $receiver]);
Tag::store($uriid, $type, $name, $receiver, $target);
foreach ($receivers[$element] ?? [] as $receiver) {
if ($receiver == ActivityPub::PUBLIC_COLLECTION) {
$name = Receiver::PUBLIC_COLLECTION;
} elseif ($path = parse_url($receiver, PHP_URL_PATH)) {
$name = trim($path, '/');
} elseif ($host = parse_url($receiver, PHP_URL_HOST)) {
$name = $host;
} else {
Logger::warning('Unable to coerce name from receiver', ['element' => $element, 'type' => $type, 'receiver' => $receiver]);
$name = '';
}
$target = Tag::getTargetType($receiver);
Logger::debug('Got target type', ['type' => $target, 'url' => $receiver]);
Tag::store($uriid, $type, $name, $receiver, $target);
}
}
}
private static function storeCapabilities(int $uriid, array $capabilities): array
{
$restrictions = [];
foreach (['pixelfed:canAnnounce' => Tag::CAN_ANNOUNCE, 'pixelfed:canLike' => Tag::CAN_LIKE, 'pixelfed:canReply' => Tag::CAN_REPLY] as $element => $type) {
$restricted = true;
foreach ($capabilities[$element] ?? [] as $capability) {
if ($capability == ActivityPub::PUBLIC_COLLECTION) {
$name = Receiver::PUBLIC_COLLECTION;
} elseif (empty($capability) || ($capability == '[]')) {
continue;
} elseif ($path = parse_url($capability, PHP_URL_PATH)) {
$name = trim($path, '/');
} elseif ($host = parse_url($capability, PHP_URL_HOST)) {
$name = $host;
} else {
Logger::warning('Unable to coerce name from capability', ['element' => $element, 'type' => $type, 'capability' => $capability]);
$name = '';
}
$restricted = false;
Tag::store($uriid, $type, $name, $capability);
}
if ($restricted) {
$restrictions[] = $type;
}
}
return $restrictions;
}
/**
* Creates an mail post
*

View file

@ -1943,6 +1943,10 @@ class Receiver
$object_data['receiver'] = $receivers;
$object_data['reception_type'] = $reception_types;
if (!empty($object['pixelfed:capabilities'])) {
$object_data['capabilities'] = self::getCapabilities($object);
}
$object_data['unlisted'] = in_array(-1, $object_data['receiver']);
unset($object_data['receiver'][-1]);
unset($object_data['reception_type'][-1]);
@ -1950,6 +1954,18 @@ class Receiver
return $object_data;
}
private static function getCapabilities($object) {
$capabilities = [];
foreach (['pixelfed:canAnnounce', 'pixelfed:canLike', 'pixelfed:canReply'] as $element) {
$capabilities_list = JsonLD::fetchElementArray($object['pixelfed:capabilities'], $element, '@id');
if (empty($capabilities_list)) {
continue;
}
$capabilities[$element] = $capabilities_list;
}
return $capabilities;
}
/**
* Create an object data array from a given activity
*
@ -2058,6 +2074,11 @@ class Receiver
$object_data['attachments'] = array_merge($object_data['attachments'], self::processAttachmentUrls($object['as:url'] ?? []));
}
$object_data['can-comment'] = JsonLD::fetchElement($object, 'pt:commentsEnabled', '@value');
if (is_null($object_data['can-comment'])) {
$object_data['can-comment'] = JsonLD::fetchElement($object, 'pixelfed:commentsEnabled', '@value');
}
// Support for quoted posts (Pleroma, Fedibird and Misskey)
$object_data['quote-url'] = JsonLD::fetchElement($object, 'as:quoteUrl', '@value');
if (empty($object_data['quote-url'])) {

View file

@ -171,6 +171,7 @@ class JsonLD
'mobilizon' => (object)['@id' => 'https://joinmobilizon.org/ns#', '@type' => '@id'],
'fedibird' => (object)['@id' => 'http://fedibird.com/ns#', '@type' => '@id'],
'misskey' => (object)['@id' => 'https://misskey-hub.net/ns#', '@type' => '@id'],
'pixelfed' => (object)['@id' => 'http://pixelfed.org/ns#', '@type' => '@id'],
];
$orig_json = $json;

View file

@ -395,51 +395,51 @@ as the value of $top_child_total (this is done at the end of this file)
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="dropdownMenuOptions-{{$item.id}}">
{{if $item.edpost}} {{* edit the posting *}}
<li role="menuitem">
<a href="javascript:editpost('{{$item.edpost.0}}?mode=none');" title="{{$item.edpost.1}}" class="btn-link navicon pencil"><i class="fa fa-pencil" aria-hidden="true"></i> {{$item.edpost.1}}</a>
<a href="javascript:editpost('{{$item.edpost.0}}?mode=none');" title="{{$item.edpost.1}}" class="btn-link navicon pencil"><i class="fa fa-pencil" aria-hidden="true"></i>&ensp;{{$item.edpost.1}}</a>
</li>
{{/if}}
{{if $item.tagger}} {{* tag the post *}}
<li role="menuitem">
<a id="tagger-{{$item.id}}" href="javascript:itemTag({{$item.id}});" class="btn-link {{$item.tagger.class}}" title="{{$item.tagger.add}}"><i class="fa fa-tag" aria-hidden="true"></i> {{$item.tagger.add}}</a>
<a id="tagger-{{$item.id}}" href="javascript:itemTag({{$item.id}});" class="btn-link {{$item.tagger.class}}" title="{{$item.tagger.add}}"><i class="fa fa-tag" aria-hidden="true"></i>&ensp;{{$item.tagger.add}}</a>
</li>
{{/if}}
{{if $item.filer}}
<li role="menuitem">
<a id="filer-{{$item.id}}" href="javascript:itemFiler({{$item.id}});" class="btn-link filer-item filer-icon" title="{{$item.filer}}"><i class="fa fa-folder" aria-hidden="true"></i>&nbsp;{{$item.filer}}</a>
<a id="filer-{{$item.id}}" href="javascript:itemFiler({{$item.id}});" class="btn-link filer-item filer-icon" title="{{$item.filer}}"><i class="fa fa-folder" aria-hidden="true"></i>&ensp;{{$item.filer}}</a>
</li>
{{/if}}
{{if $item.pin}}
<li role="menuitem">
<a id="pin-{{$item.id}}" href="javascript:doPin({{$item.id}});" class="btn-link {{$item.pin.classdo}}" title="{{$item.pin.do}}"><i class="fa fa-circle-o" aria-hidden="true"></i>&nbsp;{{$item.pin.do}}</a>
<a id="unpin-{{$item.id}}" href="javascript:doPin({{$item.id}});" class="btn-link {{$item.pin.classundo}}" title="{{$item.pin.undo}}"><i class="fa fa-dot-circle-o" aria-hidden="true"></i>&nbsp;{{$item.pin.undo}}</a>
<a id="pin-{{$item.id}}" href="javascript:doPin({{$item.id}});" class="btn-link {{$item.pin.classdo}}" title="{{$item.pin.do}}"><i class="fa fa-circle-o" aria-hidden="true"></i>&ensp;{{$item.pin.do}}</a>
<a id="unpin-{{$item.id}}" href="javascript:doPin({{$item.id}});" class="btn-link {{$item.pin.classundo}}" title="{{$item.pin.undo}}"><i class="fa fa-dot-circle-o" aria-hidden="true"></i>&ensp;{{$item.pin.undo}}</a>
</li>
{{/if}}
{{if $item.star}}
<li role="menuitem">
<a id="star-{{$item.id}}" href="javascript:doStar({{$item.id}});" class="btn-link {{$item.star.classdo}}" title="{{$item.star.do}}"><i class="fa fa-star-o" aria-hidden="true"></i>&nbsp;{{$item.star.do}}</a>
<a id="unstar-{{$item.id}}" href="javascript:doStar({{$item.id}});" class="btn-link {{$item.star.classundo}}" title="{{$item.star.undo}}"><i class="fa fa-star" aria-hidden="true"></i>&nbsp;{{$item.star.undo}}</a>
<a id="star-{{$item.id}}" href="javascript:doStar({{$item.id}});" class="btn-link {{$item.star.classdo}}" title="{{$item.star.do}}"><i class="fa fa-star-o" aria-hidden="true"></i>&ensp;{{$item.star.do}}</a>
<a id="unstar-{{$item.id}}" href="javascript:doStar({{$item.id}});" class="btn-link {{$item.star.classundo}}" title="{{$item.star.undo}}"><i class="fa fa-star" aria-hidden="true"></i>&ensp;{{$item.star.undo}}</a>
</li>
{{/if}}
{{if $item.follow_thread}}
<li role="menuitem">
<a id="follow_thread-{{$item.id}}" href="javascript:{{$item.follow_thread.action}}" class="btn-link" title="{{$item.follow_thread.title}}"><i class="fa fa-plus" aria-hidden="true"></i>&nbsp;{{$item.follow_thread.title}}</a>
<a id="follow_thread-{{$item.id}}" href="javascript:{{$item.follow_thread.action}}" class="btn-link" title="{{$item.follow_thread.title}}"><i class="fa fa-plus" aria-hidden="true"></i>&ensp;{{$item.follow_thread.title}}</a>
</li>
{{/if}}
{{if $item.language}}
<li role="menuitem">
<a id="language-{{$item.id}}" href="javascript:alert('{{$item.language.1}}');" class="btn-link filer-item language-icon" title="{{$item.language.0}}"><i class="fa fa-language" aria-hidden="true"></i>&nbsp;{{$item.language.0}}</a>
<a id="language-{{$item.id}}" href="javascript:alert('{{$item.language.1}}');" class="btn-link filer-item language-icon" title="{{$item.language.0}}"><i class="fa fa-language" aria-hidden="true"></i>&ensp;{{$item.language.0}}</a>
</li>
{{/if}}
{{if $item.browsershare}}
<li role="menuitem" class="button-browser-share">
<a id="browser-share-{{$item.id}}" href="javascript:navigator.share({url: '{{$item.plink.orig}}'})" class="btn-link button-browser-share" title="{{$item.browsershare.1}}"><i class="fa fa-share-alt" aria-hidden="true"></i>&nbsp;{{$item.browsershare.0}}</a>
<a id="browser-share-{{$item.id}}" href="javascript:navigator.share({url: '{{$item.plink.orig}}'})" class="btn-link button-browser-share" title="{{$item.browsershare.1}}"><i class="fa fa-share-alt" aria-hidden="true"></i>&ensp;{{$item.browsershare.0}}</a>
</li>
{{/if}}
@ -449,42 +449,42 @@ as the value of $top_child_total (this is done at the end of this file)
{{if $item.ignore}}
<li role="menuitem">
<a id="ignore-{{$item.id}}" href="javascript:doIgnoreThread({{$item.id}});" class="btn-link {{$item.ignore.classdo}}" title="{{$item.ignore.do}}"><i class="fa fa-bell-slash" aria-hidden="true"></i> {{$item.ignore.do}}</a>
<a id="ignore-{{$item.id}}" href="javascript:doIgnoreThread({{$item.id}});" class="btn-link {{$item.ignore.classdo}}" title="{{$item.ignore.do}}"><i class="fa fa-bell-slash" aria-hidden="true"></i>&ensp;{{$item.ignore.do}}</a>
</li>
<li role="menuitem">
<a id="unignore-{{$item.id}}" href="javascript:doIgnoreThread({{$item.id}});" class="btn-link {{$item.ignore.classundo}}" title="{{$item.ignore.undo}}"><i class="fa fa-bell" aria-hidden="true"></i> {{$item.ignore.undo}}</a>
<a id="unignore-{{$item.id}}" href="javascript:doIgnoreThread({{$item.id}});" class="btn-link {{$item.ignore.classundo}}" title="{{$item.ignore.undo}}"><i class="fa fa-bell" aria-hidden="true"></i>&ensp;{{$item.ignore.undo}}</a>
</li>
{{/if}}
{{if $item.drop && $item.drop.dropping}}
<li role="menuitem">
<a class="btn-link navicon delete" href="javascript:dropItem('item/drop/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.drop.label}}"><i class="fa fa-trash" aria-hidden="true"></i> {{$item.drop.label}}</a>
<a class="btn-link navicon delete" href="javascript:dropItem('item/drop/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.drop.label}}"><i class="fa fa-trash" aria-hidden="true"></i>&ensp;{{$item.drop.label}}</a>
</li>
{{/if}}
{{if $item.block}}
<li role="menuitem">
<a class="btn-link navicon block" href="javascript:blockAuthor('item/block/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.block.label}}"><i class="fa fa-ban" aria-hidden="true"></i> {{$item.block.label}}</a>
<a class="btn-link navicon block" href="javascript:blockAuthor('item/block/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.block.label}}"><i class="fa fa-ban" aria-hidden="true"></i>&ensp;{{$item.block.label}}</a>
</li>
{{/if}}
{{if $item.ignore_author}}
<li role="menuitem">
<a class="btn-link navicon ignore" href="javascript:ignoreAuthor('item/ignore/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.ignore_author.label}}"><i class="fa fa-eye-slash" aria-hidden="true"></i> {{$item.ignore_author.label}}</a>
<a class="btn-link navicon ignore" href="javascript:ignoreAuthor('item/ignore/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.ignore_author.label}}"><i class="fa fa-eye-slash" aria-hidden="true"></i>&ensp;{{$item.ignore_author.label}}</a>
</li>
{{/if}}
{{if $item.collapse}}
<li role="menuitem">
<a class="btn-link navicon collapse" href="javascript:collapseAuthor('item/collapse/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.collapse.label}}"><i class="fa fa-minus-square" aria-hidden="true"></i> {{$item.collapse.label}}</a>
<a class="btn-link navicon collapse" href="javascript:collapseAuthor('item/collapse/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.collapse.label}}"><i class="fa fa-minus-square" aria-hidden="true"></i>&ensp;{{$item.collapse.label}}</a>
</li>
{{/if}}
{{if $item.ignore_server}}
<li role="menuitem">
<a class="btn-link navicon ignoreServer" href="javascript:ignoreServer('settings/server/{{$item.author_gsid}}/ignore', 'item-{{$item.guid}}');" title="{{$item.ignore_server.label}}"><i class="fa fa-eye-slash" aria-hidden="true"></i> {{$item.ignore_server.label}}</a>
<a class="btn-link navicon ignoreServer" href="javascript:ignoreServer('settings/server/{{$item.author_gsid}}/ignore', 'item-{{$item.guid}}');" title="{{$item.ignore_server.label}}"><i class="fa fa-eye-slash" aria-hidden="true"></i>&ensp;{{$item.ignore_server.label}}</a>
</li>
{{/if}}
{{if $item.report}}
<li role="menuitem">
<a class="btn-link navicon ignore" href="{{$item.report.href}}"><i class="fa fa-flag" aria-hidden="true"></i> {{$item.report.label}}</a>
<a class="btn-link navicon ignore" href="{{$item.report.href}}"><i class="fa fa-flag" aria-hidden="true"></i>&ensp;{{$item.report.label}}</a>
</li>
{{/if}}
</ul>
@ -578,45 +578,45 @@ as the value of $top_child_total (this is done at the end of this file)
<ul class="dropdown-menu dropdown-menu-right" role="menu" aria-labelledby="dropdownMenuOptions-{{$item.id}}">
{{if $item.edpost}} {{* edit the posting *}}
<li role="menuitem">
<a href="javascript:editpost('{{$item.edpost.0}}?mode=none');" title="{{$item.edpost.1}}" class="btn-link navicon pencil"><i class="fa fa-pencil" aria-hidden="true"></i> {{$item.edpost.1}}</a>
<a href="javascript:editpost('{{$item.edpost.0}}?mode=none');" title="{{$item.edpost.1}}" class="btn-link navicon pencil"><i class="fa fa-pencil" aria-hidden="true"></i>&ensp;{{$item.edpost.1}}</a>
</li>
{{/if}}
{{if $item.tagger}} {{* tag the post *}}
<li role="menuitem">
<a id="tagger-{{$item.id}}" href="javascript:itemTag({{$item.id}});" class="btn-link {{$item.tagger.class}}" title="{{$item.tagger.add}}"><i class="fa fa-tag" aria-hidden="true"></i> {{$item.tagger.add}}</a>
<a id="tagger-{{$item.id}}" href="javascript:itemTag({{$item.id}});" class="btn-link {{$item.tagger.class}}" title="{{$item.tagger.add}}"><i class="fa fa-tag" aria-hidden="true"></i>&ensp;{{$item.tagger.add}}</a>
</li>
{{/if}}
{{if $item.filer}}
<li role="menuitem">
<a id="filer-{{$item.id}}" href="javascript:itemFiler({{$item.id}});" class="btn-link filer-item filer-icon" title="{{$item.filer}}"><i class="fa fa-folder" aria-hidden="true"></i>&nbsp;{{$item.filer}}</a>
<a id="filer-{{$item.id}}" href="javascript:itemFiler({{$item.id}});" class="btn-link filer-item filer-icon" title="{{$item.filer}}"><i class="fa fa-folder" aria-hidden="true"></i>&ensp;{{$item.filer}}</a>
</li>
{{/if}}
{{if $item.pin}}
<li role="menuitem">
<a id="pin-{{$item.id}}" href="javascript:doPin({{$item.id}});" class="btn-link {{$item.pin.classdo}}" title="{{$item.pin.do}}"><i class="fa fa-circle-o" aria-hidden="true"></i>&nbsp;{{$item.pin.do}}</a>
<a id="unpin-{{$item.id}}" href="javascript:doPin({{$item.id}});" class="btn-link {{$item.pin.classundo}}" title="{{$item.pin.undo}}"><i class="fa fa-dot-circle-o" aria-hidden="true"></i>&nbsp;{{$item.pin.undo}}</a>
<a id="pin-{{$item.id}}" href="javascript:doPin({{$item.id}});" class="btn-link {{$item.pin.classdo}}" title="{{$item.pin.do}}"><i class="fa fa-circle-o" aria-hidden="true"></i>&ensp;{{$item.pin.do}}</a>
<a id="unpin-{{$item.id}}" href="javascript:doPin({{$item.id}});" class="btn-link {{$item.pin.classundo}}" title="{{$item.pin.undo}}"><i class="fa fa-dot-circle-o" aria-hidden="true"></i>&ensp;{{$item.pin.undo}}</a>
</li>
{{/if}}
{{if $item.star}}
<li role="menuitem">
<a id="star-{{$item.id}}" href="javascript:doStar({{$item.id}});" class="btn-link {{$item.star.classdo}}" title="{{$item.star.do}}"><i class="fa fa-star-o" aria-hidden="true"></i>&nbsp;{{$item.star.do}}</a>
<a id="unstar-{{$item.id}}" href="javascript:doStar({{$item.id}});" class="btn-link {{$item.star.classundo}}" title="{{$item.star.undo}}"><i class="fa fa-star" aria-hidden="true"></i>&nbsp;{{$item.star.undo}}</a>
<a id="star-{{$item.id}}" href="javascript:doStar({{$item.id}});" class="btn-link {{$item.star.classdo}}" title="{{$item.star.do}}"><i class="fa fa-star-o" aria-hidden="true"></i>&ensp;{{$item.star.do}}</a>
<a id="unstar-{{$item.id}}" href="javascript:doStar({{$item.id}});" class="btn-link {{$item.star.classundo}}" title="{{$item.star.undo}}"><i class="fa fa-star" aria-hidden="true"></i>&ensp;{{$item.star.undo}}</a>
</li>
{{/if}}
{{if $item.follow_thread}}
<li role="menuitem">
<a id="follow_thread-{{$item.id}}" href="javascript:{{$item.follow_thread.action}}" class="btn-link" title="{{$item.follow_thread.title}}"><i class="fa fa-plus" aria-hidden="true"></i>&nbsp;{{$item.follow_thread.title}}</a>
<a id="follow_thread-{{$item.id}}" href="javascript:{{$item.follow_thread.action}}" class="btn-link" title="{{$item.follow_thread.title}}"><i class="fa fa-plus" aria-hidden="true"></i>&ensp;{{$item.follow_thread.title}}</a>
</li>
{{/if}}
{{if $item.language}}
<li role="menuitem">
<a id="language-{{$item.id}}" href="javascript:alert('{{$item.language.1}}');" class="btn-link filer-item language-icon" title="{{$item.language.0}}"><i class="fa fa-language" aria-hidden="true"></i>&nbsp;{{$item.language.0}}</a>
<a id="language-{{$item.id}}" href="javascript:alert('{{$item.language.1}}');" class="btn-link filer-item language-icon" title="{{$item.language.0}}"><i class="fa fa-language" aria-hidden="true"></i>&ensp;{{$item.language.0}}</a>
</li>
{{/if}}
@ -627,42 +627,42 @@ as the value of $top_child_total (this is done at the end of this file)
{{if $item.ignore}}
<li role="menuitem">
<a id="ignore-{{$item.id}}" href="javascript:doIgnoreThread({{$item.id}});" class="btn-link {{$item.ignore.classdo}}" title="{{$item.ignore.do}}"><i class="fa fa-bell-slash" aria-hidden="true"></i> {{$item.ignore.do}}</a>
<a id="ignore-{{$item.id}}" href="javascript:doIgnoreThread({{$item.id}});" class="btn-link {{$item.ignore.classdo}}" title="{{$item.ignore.do}}"><i class="fa fa-bell-slash" aria-hidden="true"></i>&ensp;{{$item.ignore.do}}</a>
</li>
<li role="menuitem">
<a id="unignore-{{$item.id}}" href="javascript:doIgnoreThread({{$item.id}});" class="btn-link {{$item.ignore.classundo}}" title="{{$item.ignore.undo}}"><i class="fa fa-bell" aria-hidden="true"></i> {{$item.ignore.undo}}</a>
<a id="unignore-{{$item.id}}" href="javascript:doIgnoreThread({{$item.id}});" class="btn-link {{$item.ignore.classundo}}" title="{{$item.ignore.undo}}"><i class="fa fa-bell" aria-hidden="true"></i>&ensp;{{$item.ignore.undo}}</a>
</li>
{{/if}}
{{if $item.drop && $item.drop.dropping}}
<li role="menuitem">
<a class="btn-link navicon delete" href="javascript:dropItem('item/drop/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.drop.label}}"><i class="fa fa-trash" aria-hidden="true"></i> {{$item.drop.label}}</a>
<a class="btn-link navicon delete" href="javascript:dropItem('item/drop/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.drop.label}}"><i class="fa fa-trash" aria-hidden="true"></i>&ensp;{{$item.drop.label}}</a>
</li>
{{/if}}
{{if $item.block}}
<li role="menuitem">
<a class="btn-link navicon block" href="javascript:blockAuthor('item/block/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.block.label}}"><i class="fa fa-ban" aria-hidden="true"></i> {{$item.block.label}}</a>
<a class="btn-link navicon block" href="javascript:blockAuthor('item/block/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.block.label}}"><i class="fa fa-ban" aria-hidden="true"></i>&ensp;{{$item.block.label}}</a>
</li>
{{/if}}
{{if $item.ignore_author}}
<li role="menuitem">
<a class="btn-link navicon ignore" href="javascript:ignoreAuthor('item/ignore/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.ignore_author.label}}"><i class="fa fa-eye-slash" aria-hidden="true"></i> {{$item.ignore_author.label}}</a>
<a class="btn-link navicon ignore" href="javascript:ignoreAuthor('item/ignore/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.ignore_author.label}}"><i class="fa fa-eye-slash" aria-hidden="true"></i>&ensp;{{$item.ignore_author.label}}</a>
</li>
{{/if}}
{{if $item.collapse}}
<li role="menuitem">
<a class="btn-link navicon collapse" href="javascript:collapseAuthor('item/collapse/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.collapse.label}}"><i class="fa fa-minus-square" aria-hidden="true"></i> {{$item.collapse.label}}</a>
<a class="btn-link navicon collapse" href="javascript:collapseAuthor('item/collapse/{{$item.id}}', 'item-{{$item.guid}}');" title="{{$item.collapse.label}}"><i class="fa fa-minus-square" aria-hidden="true"></i>&ensp;{{$item.collapse.label}}</a>
</li>
{{/if}}
{{if $item.ignore_server}}
<li role="menuitem">
<a class="btn-link navicon ignoreServer" href="javascript:ignoreServer('settings/server/{{$item.author_gsid}}/ignore', 'item-{{$item.guid}}');" title="{{$item.ignore_server.label}}"><i class="fa fa-eye-slash" aria-hidden="true"></i> {{$item.ignore_server.label}}</a>
<a class="btn-link navicon ignoreServer" href="javascript:ignoreServer('settings/server/{{$item.author_gsid}}/ignore', 'item-{{$item.guid}}');" title="{{$item.ignore_server.label}}"><i class="fa fa-eye-slash" aria-hidden="true"></i>&ensp;{{$item.ignore_server.label}}</a>
</li>
{{/if}}
{{if $item.report}}
<li role="menuitem">
<a class="btn-link navicon ignore" href="{{$item.report.href}}"><i class="fa fa-flag" aria-hidden="true"></i> {{$item.report.label}}</a>
<a class="btn-link navicon ignore" href="{{$item.report.href}}"><i class="fa fa-flag" aria-hidden="true"></i>&ensp;{{$item.report.label}}</a>
</li>
{{/if}}
</ul>