diff --git a/plugins/Favourite/Favourite.php b/plugins/Favourite/Favourite.php
index 524f2f8c4e..c67fd6b832 100644
--- a/plugins/Favourite/Favourite.php
+++ b/plugins/Favourite/Favourite.php
@@ -51,7 +51,7 @@ class Favourite extends NoteHandlerPlugin
*/
public function onAddNoteActions(Request $request, Note $note, array &$actions): bool
{
- if (($user = Common::user()) === null) {
+ if (is_null($user = Common::user())) {
return Event::next;
}
diff --git a/plugins/Favourite/templates/favourite/add_to_favourites.html.twig b/plugins/Favourite/templates/favourite/add_to_favourites.html.twig
index f6b23ece00..680108970b 100644
--- a/plugins/Favourite/templates/favourite/add_to_favourites.html.twig
+++ b/plugins/Favourite/templates/favourite/add_to_favourites.html.twig
@@ -1,4 +1,5 @@
{% extends 'stdgrid.html.twig' %}
+{% import "/cards/note/view.html.twig" as noteView %}
{% block title %}{{ 'Favourite ' | trans }}{{ note.getActorNickname() }}{{ '\'s note.' | trans }}{% endblock %}
@@ -11,7 +12,7 @@
{{ parent() }}
- {% include '/cards/note/view.html.twig' with {'note': note, 'note_actions_show': false} only %}
+ {{ noteView.macro_note_minimal(note) }}
{{ form(add_favourite) }}
diff --git a/plugins/Favourite/templates/favourite/remove_from_favourites.html.twig b/plugins/Favourite/templates/favourite/remove_from_favourites.html.twig
index 225d3c3a0e..27be98b850 100644
--- a/plugins/Favourite/templates/favourite/remove_from_favourites.html.twig
+++ b/plugins/Favourite/templates/favourite/remove_from_favourites.html.twig
@@ -1,4 +1,5 @@
{% extends 'stdgrid.html.twig' %}
+{% import "/cards/note/view.html.twig" as noteView %}
{% block title %}{{ 'Remove favourite from ' | trans }}{{ note.getActorNickname() }}{{ '\'s note.' | trans }}{% endblock %}
@@ -11,7 +12,7 @@
{{ parent() }}
- {% include '/cards/note/view.html.twig' with {'note': note, 'note_actions_show': false} only %}
+ {{ noteView.macro_note_minimal(note) }}
{{ form(remove_favourite) }}
diff --git a/plugins/Repeat/Controller/Repeat.php b/plugins/Repeat/Controller/Repeat.php
new file mode 100644
index 0000000000..c9bb8fcf07
--- /dev/null
+++ b/plugins/Repeat/Controller/Repeat.php
@@ -0,0 +1,145 @@
+.
+
+// }}}
+
+namespace Plugin\Repeat\Controller;
+
+use App\Core\Controller;
+use App\Core\DB\DB;
+use App\Core\Event;
+use App\Core\Form;
+use App\Core\Router\Router;
+use App\Entity\Note;
+use App\Util\Common;
+use App\Util\Exception\InvalidFormException;
+use App\Util\Exception\NoLoggedInUser;
+use App\Util\Exception\NoSuchNoteException;
+use App\Util\Exception\RedirectException;
+use Symfony\Component\Form\Extension\Core\Type\SubmitType;
+use Symfony\Component\HttpFoundation\Request;
+use function App\Core\I18n\_m;
+
+class Repeat extends Controller
+{
+
+ /**
+ * @throws RedirectException
+ * @throws NoSuchNoteException
+ * @throws InvalidFormException
+ * @throws \App\Util\Exception\ServerException
+ * @throws NoLoggedInUser
+ */
+ public function repeatAddNote(Request $request, int $id): bool|array
+ {
+ $user = Common::ensureLoggedIn();
+ $opts = ['actor_id' => $user->getId(), 'repeat_of' => $id];
+ $note_already_repeated = DB::count('note', $opts) >= 1;
+ if (is_null($note_already_repeated)) {
+ throw new NoSuchNoteException();
+ }
+
+ $note = Note::getWithPK(['id' => $id]);
+ $form_add_to_repeat = Form::create([
+ ['add_repeat', SubmitType::class,
+ [
+ 'label' => _m('Repeat note!'),
+ 'attr' => [
+ 'title' => _m('Repeat this note!')
+ ],
+ ],
+ ],
+ ]);
+
+ $form_add_to_repeat->handleRequest($request);
+ if ($form_add_to_repeat->isSubmitted()) {
+ if (!is_null($note)) {
+ DB::persist(Note::create([
+ 'actor_id' => $user->getId(),
+ 'repeat_of' => $note->getId(),
+ 'content' => $note->getContent(),
+ 'content_type' => $note->getContentType(),
+ 'rendered' => $note->getRendered(),
+ 'is_local' => true,
+ ]));
+ DB::flush();
+ }
+
+ if (array_key_exists('from', $get_params = $this->params())) {
+ # TODO anchor on element id
+ throw new RedirectException($get_params['from']);
+ }
+ }
+
+ return [
+ '_template' => 'repeat/add_to_repeats.html.twig',
+ 'note' => $note,
+ 'add_repeat' => $form_add_to_repeat->createView(),
+ ];
+ }
+
+ /**
+ * @throws RedirectException
+ * @throws NoSuchNoteException
+ * @throws InvalidFormException
+ * @throws \App\Util\Exception\ServerException
+ * @throws NoLoggedInUser
+ */
+ public function repeatRemoveNote(Request $request, int $id): array
+ {
+ $user = Common::ensureLoggedIn();
+ $opts = ['note_id' => $id, 'actor_id' => $user->getId()];
+ $remove_repeat_note = DB::find('note', $opts);
+ if (is_null($remove_repeat_note)) {
+ throw new NoSuchNoteException();
+ }
+
+ $form_remove_repeat = Form::create([
+ ['remove_repeat', SubmitType::class,
+ [
+ 'label' => _m('Remove repeat'),
+ 'attr' => [
+ 'title' => _m('Remove note from repeats.')
+ ],
+ ],
+ ],
+ ]);
+
+ $form_remove_repeat->handleRequest($request);
+ if ($form_remove_repeat->isSubmitted()) {
+ if ($remove_repeat_note) {
+ DB::remove($remove_repeat_note);
+ DB::flush();
+ }
+
+ if (array_key_exists('from', $get_params = $this->params())) {
+ # TODO anchor on element id
+ throw new RedirectException($get_params['from']);
+ }
+ }
+
+ return [
+ '_template' => 'repeat/remove_from_repeats.html.twig',
+ 'note' => $remove_repeat_note,
+ 'remove_repeat' => $form_remove_repeat->createView(),
+ ];
+ }
+}
diff --git a/plugins/Repeat/Repeat.php b/plugins/Repeat/Repeat.php
index 800500ecad..c4ac7b3f34 100644
--- a/plugins/Repeat/Repeat.php
+++ b/plugins/Repeat/Repeat.php
@@ -23,77 +23,66 @@ namespace Plugin\Repeat;
use App\Core\DB\DB;
use App\Core\Event;
-use App\Core\Form;
-use function App\Core\I18n\_m;
+use App\Core\Router\RouteLoader;
+use App\Core\Router\Router;
+use App\Util\Exception\InvalidFormException;
+use App\Util\Exception\NoSuchNoteException;
use App\Core\Modules\NoteHandlerPlugin;
use App\Entity\Note;
use App\Util\Common;
use App\Util\Exception\RedirectException;
-use Symfony\Component\Form\Extension\Core\Type\HiddenType;
-use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
class Repeat extends NoteHandlerPlugin
{
- // TODO: Refactoring to link instead of a form
+
/**
* HTML rendering event that adds the repeat form as a note
* action, if a user is logged in
*
+ * @throws InvalidFormException
+ * @throws NoSuchNoteException
* @throws RedirectException
+ *
+ * @return bool Event hook
*/
-/* public function onAddNoteActions(Request $request, Note $note, array &$actions)
+ public function onAddNoteActions(Request $request, Note $note, array &$actions): bool
{
- if (($user = Common::user()) === null) {
+ if (is_null($user = Common::user())) {
return Event::next;
}
- $opts = ['actor_id' => $user->getId(), 'repeat_of' => $note->getId()];
- $is_set = DB::count('note', $opts) == 1;
- $form_repeat = Form::create([
- ['submit_repeat', SubmitType::class,
- [
- 'label' => ' ',
- 'attr' => [
- 'class' => ($is_set ? 'note-actions-set' : 'note-actions-unset') . ' button-container repeat-button-container',
- 'title' => $is_set ? _m('Note already repeated!') : _m('Repeat this note!'),
- ],
- ],
- ],
- ['note_id', HiddenType::class, ['data' => $note->getId()]],
- ["repeat-{$note->getId()}", HiddenType::class, ['data' => $is_set ? '1' : '0']],
- ]);
+ // If note is repeat, "is_repeated" is 1
+ $opts = ['actor_id' => $user->getId(), 'repeat_of' => $note->getId()];
+ $is_repeated = DB::count('note', $opts) >= 1;
- // Handle form
- $ret = self::noteActionHandle(
- $request,
- $form_repeat,
- $note,
- "repeat-{$note->getId()}",
- function ($note, $data, $user) {
- if ($data["repeat-{$note->getId()}"] === '0') {
- DB::persist(Note::create([
- 'actor_id' => $user->getId(),
- 'repeat_of' => $note->getId(),
- 'content' => $note->getContent(),
- 'is_local' => true,
- ]));
- } else {
- DB::remove(DB::findOneBy('note', ['actor_id' => $user->getId(), 'repeat_of' => $note->getId()]));
- }
- DB::flush();
+ // Generating URL for repeat action route
+ $args = ['id' => $note->getId()];
+ $type = Router::ABSOLUTE_PATH;
+ $repeat_action_url = $is_repeated ?
+ Router::url('repeat_remove', $args, $type) :
+ Router::url('repeat_add', $args, $type);
- // Prevent accidental refreshes from resubmitting the form
- throw new RedirectException();
+ // Concatenating get parameter to redirect the user to where he came from
+ $repeat_action_url .= '?from=' . substr($request->getQueryString(), 2);
- return Event::stop;
- },
- );
+ $extra_classes = $is_repeated ? "note-actions-set" : "note-actions-unset";
+ $repeat_action = [
+ "url" => $repeat_action_url,
+ "classes" => "button-container repeat-button-container $extra_classes",
+ "id" => "repeat-button-container-" . $note->getId()
+ ];
- if ($ret !== null) {
- return $ret;
- }
- $actions[] = $form_repeat->createView();
+ $actions[] = $repeat_action;
return Event::next;
- }*/
+ }
+
+ public function onAddRoute(RouteLoader $r): bool
+ {
+ // Add/remove note to/from repeats
+ $r->connect(id: 'repeat_add', uri_path: '/object/note/{id<\d+>}/repeat', target: [Controller\Repeat::class, 'repeatAddNote']);
+ $r->connect(id: 'repeat_remove', uri_path: '/object/note/{id<\d+>}/unrepeat', target: [Controller\Repeat::class, 'repeatRemoveNote']);
+
+ return Event::next;
+ }
}
diff --git a/plugins/Repeat/templates/repeat/add_to_repeats.html.twig b/plugins/Repeat/templates/repeat/add_to_repeats.html.twig
new file mode 100644
index 0000000000..539b9aa606
--- /dev/null
+++ b/plugins/Repeat/templates/repeat/add_to_repeats.html.twig
@@ -0,0 +1,19 @@
+{% extends 'stdgrid.html.twig' %}
+{% import "/cards/note/view.html.twig" as noteView %}
+
+{% block title %}{{ 'Repeat ' | trans }}{{ note.getActorNickname() }}{{ '\'s note.' | trans }}{% endblock %}
+
+{% block stylesheets %}
+ {{ parent() }}
+
+
+ {{ noteView.macro_note_minimal(note) }}
+ {{ form(add_repeat) }}
+
+
+{% endblock body %}
diff --git a/plugins/Repeat/templates/repeat/remove_from_repeats.html.twig b/plugins/Repeat/templates/repeat/remove_from_repeats.html.twig
new file mode 100644
index 0000000000..a38a8a4ebc
--- /dev/null
+++ b/plugins/Repeat/templates/repeat/remove_from_repeats.html.twig
@@ -0,0 +1,19 @@
+{% extends 'stdgrid.html.twig' %}
+{% import "/cards/note/view.html.twig" as noteView %}
+
+{% block title %}{{ 'Remove repeat from ' | trans }}{{ note.getActorNickname() }}{{ '\'s note.' | trans }}{% endblock %}
+
+{% block stylesheets %}
+ {{ parent() }}
+
+
+ {{ noteView.macro_note_minimal(note) }}
+ {{ form(remove_favourite) }}
+
+
+{% endblock body %}
diff --git a/public/assets/default_theme/css/base.css b/public/assets/default_theme/css/base.css
index afe26337b3..9ea839d2c1 100644
--- a/public/assets/default_theme/css/base.css
+++ b/public/assets/default_theme/css/base.css
@@ -616,7 +616,8 @@ html {
border-radius: var(--smaller);
}
50% {
- -webkit-border-radius: var(--smaller);
+ -webkit-border-rns
+Enable/disabadius: var(--smaller);
border-radius: var(--smaller);
-webkit-box-shadow: inset 0 20px 40px #FFF;
box-shadow: inset 0 20px 40px #FFF;
@@ -818,4 +819,4 @@ html {
border-radius: var(--smaller);
}
}
-}
+}
\ No newline at end of file
diff --git a/public/components/Right/assets/css/view.css b/public/components/Right/assets/css/view.css
index cb3041f2e4..0c3acc4d5b 100644
--- a/public/components/Right/assets/css/view.css
+++ b/public/components/Right/assets/css/view.css
@@ -16,6 +16,10 @@
border: 2px solid transparent;
}
+.section-panel-right textarea {
+ resize: vertical;
+}
+
@media only screen and (min-width: 1281px) {
.panel-right-icon {
display: none;
diff --git a/templates/cards/note/view.html.twig b/templates/cards/note/view.html.twig
index b416bfe882..76ec608f11 100644
--- a/templates/cards/note/view.html.twig
+++ b/templates/cards/note/view.html.twig
@@ -1,74 +1,120 @@
-{% set nickname = note.getActorNickname() %}
-{% set fullname = note.getActorFullname() %}
-{% set actor_url = note.getActor().getUrl() %}
-{% if note_actions_show is not defined %} {% set note_actions_show = true %} {% endif %}
+{% block note_actions %}
+ {% if app.user or note_actions_hide is defined %}
+
+{% block note_reply_to %}
+ {% set reply_to = note.getReplyToNickname()%}
+ {% if reply_to is not null %}
+ {% trans with {'%name%': reply_to} %} in reply to %name% {% endtrans %}
+ {% endif %}
+{% endblock note_reply_to %}
+
+{% block note_replies %}
+ {% if replies is defined and replies is not empty %}
+
+ {% for conversation in replies %}
+ {{ _self.macro_note(conversation['note'], conversation['replies']) }}
+
+ {% endfor %}
+
+ {% endif %}
+{% endblock note_replies %}
+
+{% block note_attachments %}
+ {% if hide_attachments is not defined %}
+ {% if note.getAttachments() is not empty %}
+
+ {% for attachment in note.getAttachments() %}
+ {% include '/cards/attachments/view.html.twig' with {'attachment': attachment, 'note': note} only%}
+ {% endfor %}
+
+ {% endif %}
+ {% endif %}
+{% endblock note_attachments %}
+
+{% block note_links %}
+ {% if note.getLinks() is not empty %}
+
+ {% for link in note.getLinks() %}
+ {% for block in handle_event('ViewLink', {'link': link, 'note': note}) %}
+ {{ block | raw }}
+ {% endfor %}
+ {% endfor %}
+
+ {% endif %}
+{% endblock note_links %}
+
+{% block note_text %}
+
+ {{ note.getRendered() | raw }}
+
+{% endblock note_text %}
+
+{% block note_author %}
+ {# Microformat's h-card properties indicates a face icon is a "u-logo" #}
+
+
+ {% if fullname is defined %}
+ {{ fullname }}
+ {% else %}
+ {{ nickname }}
+ {% endif %}
+
+ {{ nickname }}
+
+{% endblock note_author %}
+
+{% block note_sidebar %}
+{% endblock note_sidebar %}
-
+{% macro macro_note(note, replies) %}
+ {% set nickname = note.getActorNickname() %}
+ {% set fullname = note.getActorFullname() %}
+ {% set actor_url = note.getActor().getUrl() %}
- {# TODO: this should link to the note's user profile? #}
-
- {# Microformat's h-card properties indicates a face icon is a "u-logo" #}
-
- {{ fullname }}
- {{ nickname }}
-
-
- {% if app.user and note_actions_show %}
-
- {% for current_action in get_note_actions(note) %}
-
- {% endfor %}
-
- {% endif %}
-
- {% set reply_to = note.getReplyToNickname() %}
- {% if reply_to is not null and not skip_reply_to is defined %}
- {% trans with {'%name%': reply_to} %} in reply to %name% {% endtrans %}
- {% endif %}
+
+ {{ block('note_sidebar') }}
+
+
+ {{ block('note_author') }}
+ {{ block('note_reply_to') }}
+ {{ block('note_actions') }}
+
+
+ {{ block('note_text') }}
+ {{ block('note_attachments') }}
+ {{ block('note_links') }}
+
+ {{ block('note_replies') }}
+
+{% endmacro macro_note %}
-
-
- {{ note.getRendered() | raw }}
+{% macro macro_note_minimal(note) %}
+ {% set nickname = note.getActorNickname() %}
+ {% set fullname = note.getActorFullname() %}
+ {% set actor_url = note.getActor().getUrl() %}
+
+
+ {{ block('note_sidebar') }}
+
+
+ {{ block('note_author') }}
-
- {% if hide_attachments is not defined %}
- {% if note.getAttachments() is not empty %}
-
- {% for attachment in note.getAttachments() %}
- {% include '/cards/attachments/view.html.twig' with {'attachment': attachment, 'note': note} only%}
- {% endfor %}
-
- {% endif %}
- {% endif %}
-
- {% if note.getLinks() is not empty %}
-
- {% for link in note.getLinks() %}
- {% for block in handle_event('ViewLink', {'link': link, 'note': note}) %}
- {{ block | raw }}
- {% endfor %}
- {% endfor %}
-
- {% endif %}
-
-
- {% if replies is defined and replies is not empty %}
-
- {% for conversation in replies %}
- {% include '/note/view.html.twig' with {'note': conversation['note'], 'skip_reply_to': true, 'have_user': have_user, 'replies': conversation['replies']} only %}
- {% endfor %}
-
- {% endif %}
-
- {% if reply_to is not empty %}
-
- {% endif %}
-
-
-
+
+ {{ block('note_text') }}
+ {{ block('note_attachments') }}
+ {{ block('note_links') }}
+
+
+
+{% endmacro macro_note_minimal %}
\ No newline at end of file
diff --git a/templates/network/feed.html.twig b/templates/network/feed.html.twig
index 99cd1b1488..2bee320800 100644
--- a/templates/network/feed.html.twig
+++ b/templates/network/feed.html.twig
@@ -1,4 +1,5 @@
{% extends 'stdgrid.html.twig' %}
+{% import "/cards/note/view.html.twig" as noteView %}
{% block title %}{% if page_title is defined %}{{ page_title | trans }}{% endif %}{% endblock %}
@@ -13,7 +14,7 @@
{% if notes is defined and notes is not empty %}
{% for conversation in notes %}
- {% include '/cards/note/view.html.twig' with {'note': conversation['note'], 'replies': conversation['replies']} only %}
+ {{ noteView.macro_note(conversation['note'], conversation['replies']) }}
{% endfor %}
{% else %}