Browse Source

implement recursive mentions folding tree

main
ghost 1 year ago
parent
commit
0aca404bc0
  1. 20
      public/css/default.css
  2. 91
      src/Controller/RoomController.php
  3. 88
      templates/default/room/index.html.twig

20
public/css/default.css

@ -95,36 +95,32 @@ main ul
main ul ul main ul ul
{ {
margin-bottom: 16px; margin-left: 24px;
margin-left: 16px;
margin-top: 16px;
} }
main ul > li main ul li
{ {
margin: 8px 0; border-top: 1px var(--color-default) solid;
padding: 8px 0;
word-wrap: break-word; word-wrap: break-word;
border-bottom: 1px var(--color-default) solid;
} }
main ul > li:last-child main ul li div
{ {
border-bottom: none; padding: 16px 0;
} }
main ul > li > p main ul li p
{ {
padding: 8px 0; padding: 8px 0;
} }
main ul > li > p > br /* tmp solution for current twig filters implementation */ main ul li p > br /* tmp solution for current twig filters implementation */
{ {
display: block; display: block;
margin: 4px 0; margin: 4px 0;
} }
main ul li > span > svg main ul li span > svg
{ {
cursor: default; cursor: default;
fill: var(--color-default); fill: var(--color-default);

91
src/Controller/RoomController.php

@ -103,15 +103,24 @@ class RoomController extends AbstractController
// Require valid kevachat meta // Require valid kevachat meta
if ($data = $this->_post($pending)) if ($data = $this->_post($pending))
{ {
$feed[] = // Detect parent post
preg_match('/^@([A-z0-9]{64})\s/i', $data->message, $mention);
$feed[$data->id] =
[ [
'id' => $data->id, 'id' => $data->id,
'user' => $data->user, 'user' => $data->user,
'icon' => $data->icon, 'icon' => $data->icon,
'message' => $data->message, 'time' => $data->time,
'timestamp' => $data->time, 'parent' => isset($mention[1]) ? $mention[1] : null,
'time' => date('c', $data->time), 'message' => trim(
'pending' => true preg_replace( // remove mention from folded message
'/^@([A-z0-9]{64})\s/i',
'',
$data->message
)
),
'pending' => true
]; ];
} }
} }
@ -128,15 +137,24 @@ class RoomController extends AbstractController
// Require valid kevachat meta // Require valid kevachat meta
if ($data = $this->_post($post)) if ($data = $this->_post($post))
{ {
$feed[] = // Detect parent post
preg_match('/^@([A-z0-9]{64})\s/i', $data->message, $mention);
$feed[$data->id] =
[ [
'id' => $data->id, 'id' => $data->id,
'user' => $data->user, 'user' => $data->user,
'icon' => $data->icon, 'icon' => $data->icon,
'message' => $data->message, 'time' => $data->time,
'timestamp' => $data->time, 'parent' => isset($mention[1]) ? $mention[1] : null,
'time' => date('c', $data->time), 'message' => trim(
'pending' => false preg_replace( // remove mention from folded message
'/^@([A-z0-9]{64})\s/i',
'',
$data->message
)
),
'pending' => false
]; ];
} }
} }
@ -151,6 +169,14 @@ class RoomController extends AbstractController
$feed $feed
); );
// Init folding &data pool
$fold = $feed;
// Build threading tree
$tree = $this->_tree(
$fold
);
// RSS // RSS
if ('rss' === $request->get('feed')) if ('rss' === $request->get('feed'))
{ {
@ -176,6 +202,7 @@ class RoomController extends AbstractController
'default/room/index.html.twig', 'default/room/index.html.twig',
[ [
'feed' => $feed, 'feed' => $feed,
'tree' => $tree,
'request' => $request 'request' => $request
] ]
); );
@ -440,4 +467,36 @@ class RoomController extends AbstractController
return $identicon->getImageDataUri('webp'); return $identicon->getImageDataUri('webp');
} }
private function _tree(
array &$feed,
?string $parent = null
): array
{
$tree = [];
foreach ($feed as $post)
{
if ($post['parent'] == $parent)
{
$children = $this->_tree(
$feed,
$post['id']
);
if ($children)
{
$post['tree'] = $children;
}
$tree[$post['id']] = $post;
unset(
$feed[$post['id']]
);
}
}
return $tree;
}
} }

88
templates/default/room/index.html.twig

@ -1,3 +1,49 @@
{% macro recursive_post_tree(namespace, tree) %}
{% import _self as self %}
{% if tree | length %}
<ul>
{% for post in tree %}
<li>
<div>
<a name="{{ post.id }}"></a>
{% if post.icon %}
<img src="{{ post.icon }}" alt="icon" />
{% else %}
<strong>
@{{ 'anon' | trans }}
</strong>
{% endif %}
&bull;
<a rel="nofollow" href="{{ path('room_namespace', { namespace : namespace }) }}#{{ post.id }}" title="{{ post.time | date('c') }}">{{ post.time | format_ago }}</a>
&bull;
<a rel="nofollow" href="{{ path('room_namespace', { namespace : namespace, txid : post.id }) }}#{{ post.id }}">{{ 'reply' | trans }}</a>
{% if post.pending %}
<span title="{{ 'pending in pool' | trans }}">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71z"/>
</svg>
</span>
{% endif %}
{# apply markdown whitelist filters only to prevent ping from remote includes #}
{{
post.message | striptags
| markdown_to_html
| striptags
| message_to_markdown
| trim
| nl2br
| markdown_to_html
}}
</div>
{% if post.tree | length %}
{{ self.recursive_post_tree(namespace, post.tree) }}
{% endif %}
</li>
{% endfor %}
</ul>
{% endif %}
{% endmacro %}
{% from _self import recursive_post_tree %}
{% extends 'default/layout.html.twig' %} {% extends 'default/layout.html.twig' %}
{% block head_title_content %}{{ request.get('namespace') | keva_namespace_value }} - {{ 'KevaChat' | trans }}{% endblock %} {% block head_title_content %}{{ request.get('namespace') | keva_namespace_value }} - {{ 'KevaChat' | trans }}{% endblock %}
{% block main_content %} {% block main_content %}
@ -11,46 +57,14 @@
) )
) )
}} }}
{% if feed %} {% if tree %}
<ul> {{ recursive_post_tree(request.get('namespace'), tree) }}
{% for post in feed %}
<li>
<a name="{{ post.id }}"></a>
{% if post.icon %}
<img src="{{ post.icon }}" alt="icon" />
{% else %}
<strong>
@{{ 'anon' | trans }}
</strong>
{% endif %}
&bull;
<a rel="nofollow" href="{{ path('room_namespace', { namespace : request.get('namespace') }) }}#{{ post.id }}" title="{{ post.time }}">{{ post.timestamp | format_ago }}</a>
&bull;
<a rel="nofollow" href="{{ path('room_namespace', { namespace : request.get('namespace'), txid : post.id }) }}#{{ post.id }}">{{ 'reply' | trans }}</a>
{% if post.pending %}
<span title="{{ 'pending in pool' | trans }}">
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 16 16">
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0M8 3.5a.5.5 0 0 0-1 0V9a.5.5 0 0 0 .252.434l3.5 2a.5.5 0 0 0 .496-.868L8 8.71z"/>
</svg>
</span>
{% endif %}
{# apply markdown whitelist filters only to prevent ping from remote includes #}
{{
post.message | striptags
| markdown_to_html
| striptags
| message_to_markdown
| trim
| nl2br
| markdown_to_html
}}
</li>
{% endfor %}
</ul>
{% else %} {% else %}
<ul> <ul>
<li> <li>
{{ 'room does not contain kevachat messages' | trans }} <div>
{{ 'room does not contain kevachat messages' | trans }}
</div>
</li> </li>
</ul> </ul>
{% endif %} {% endif %}

Loading…
Cancel
Save