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() }} + +{% endblock stylesheets %} + +{% block body %} + {{ 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() }} + +{% endblock stylesheets %} + +{% block body %} + {{ 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 %} +
+ {% for current_action in get_note_actions(note) %} + + {% endfor %} +
+ {% endif %} +{% endblock note_actions %} -
+{% 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 %} + + {% 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_replies') }}
+
+{% endmacro macro_note %} - - - {% 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 %} -
- -
+ + + +{% 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 %}