diff --git a/public/assets/css/app.css b/public/assets/css/app.css index 5f3f205233ed269987e803f43addcb6b3f7c3997..021f16ebdf0e4de0bbcc74f3e514d0c7601ab989 100644 --- a/public/assets/css/app.css +++ b/public/assets/css/app.css @@ -148,6 +148,9 @@ table.label-table > tbody > tr > td { .text-grey { color:lightgrey; } +.text-dark-grey { + color: #9a9a9a; +} td:hover .fa.text-grey, p:hover .fa.text-grey, h4:hover .fa.text-grey, h1:hover .fa.text-grey { color: dimgrey; } @@ -219,12 +222,14 @@ td:hover .fa.text-light-green, p:hover .fa.text-light-green, h4:hover .fa.text-l .nav-tabs .nav-link.tab-pink { background-color: #FDF6F6; + border-color: #e5dfdf; } .nav-tabs .nav-link.tab-dark-pink { background-color: #FFE4E4; } .nav-tabs .nav-link.tab-grey { background-color: #E4E4E4; + border-color: #c4c4c4; color: grey; } .nav-tabs .nav-link { @@ -280,4 +285,9 @@ td:hover .fa.text-light-green, p:hover .fa.text-light-green, h4:hover .fa.text-l background-color: lightyellow; border: 1px solid lightgoldenrodyellow; border-radius: 3px; + border-left: 2px solid #fdac33; +} + +.border-auto { + border: 2px solid rgba(0,0,0, 0.25); } \ No newline at end of file diff --git a/src/Controller/AppBaseController.php b/src/Controller/AppBaseController.php index f5738e94552216b4c478edab566e021bb1ee134d..d7f8ffcbedd7072c87601b70ef10c4235968ecfa 100644 --- a/src/Controller/AppBaseController.php +++ b/src/Controller/AppBaseController.php @@ -293,6 +293,7 @@ class AppBaseController extends AbstractController if ($wiktionaryData) { $entry = new Entry(); + $entry->setCreatedBy($this->getUser()); $entry->setHeadword($headword); $entry->setLanguage($language); $this->doctrine->getManager()->persist($entry); @@ -323,6 +324,7 @@ class AppBaseController extends AbstractController public function createEntryInLexicon(Headword $headword, Lexicon $lexicon) { $entry = new Entry(); + $entry->setCreatedBy($this->getUser()); $this->doctrine->getManager()->persist($entry); $entry->setHeadword($headword); $entry->setLanguage($headword->getLanguage()); @@ -426,6 +428,7 @@ class AppBaseController extends AbstractController { $newWordsLexicon = $this->em->getRepository(Lexicon::class)->findOneBy(['language' => $headword->getLanguage(), 'category' => Lexicon::TYPE_NEW_WORDS]); $entry = new Entry(); + $entry->setCreatedBy($this->getUser()); $this->em->persist($entry); $entry->setHeadword($headword); $entry->setLanguage($headword->getLanguage()); diff --git a/src/Controller/EntryController.php b/src/Controller/EntryController.php index f03b557a548969c80cb5d815023c102784ddb495..9d49862002e30db244c08d60e8972c20af939c2a 100644 --- a/src/Controller/EntryController.php +++ b/src/Controller/EntryController.php @@ -8,7 +8,10 @@ use App\Entity\Lexicon; use App\Entity\Log; use App\Form\BlockType; use App\Form\CommentType; +use App\Form\DefinitionType; +use App\Form\ExampleType; use App\Form\PartOfSpeechType; +use App\Form\PronunciationType; use App\Form\SearchStringType; use App\Manager\LabelManager; use App\Repository\EntryRepository; @@ -173,18 +176,17 @@ class EntryController extends AppBaseController $propertyAccessor = PropertyAccess::createPropertyAccessor(); $block = $propertyAccessor->getValue($attributes, $blockId); - $form = $this->createForm(BlockType::class, ['block' => $block], [ + $form = $this->createForm($this->getBlockType($blockCategory), $block, [ 'action' => $this->generateUrl('app_entry_edit_block', [ 'id' => $entry->getId(), 'blockId' => $blockId, 'blockCategory' => $blockCategory, ]), - 'blockCategory' => $blockCategory, ]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $propertyAccessor->setValue($attributes, $blockId, $form->get('block')->getData()); + $propertyAccessor->setValue($attributes, $blockId, $form->getData()); $entry->setAttributes($attributes); $this->em->flush(); @@ -197,26 +199,6 @@ class EntryController extends AppBaseController ]); } - /** - * @Route("/{id}/delete-block/{blockId}", name="app_entry_delete_block", methods={"GET", "POST"}) - */ - public function deleteBlock(Request $request, Entry $entry, $blockId): Response - { - $attributes = $entry->getAttributes(); - $propertyAccessor = PropertyAccess::createPropertyAccessor(); - preg_match("/(.*)\[([^]]+)\]$/", $blockId, $matches); - $parentId = $matches[1]; - $childId = $matches[2]; - $parentBlock = $propertyAccessor->getValue($attributes, $parentId); - - unset($parentBlock[$childId]); - $propertyAccessor->setValue($attributes, $parentId, $parentBlock); - $entry->setAttributes($attributes); - $this->em->flush(); - - return $this->redirectToRoute('app_entry_show', ['id' => $entry->getId()]); - } - /** * @Route("/{id}/add-block/{blockId}", name="app_entry_add_block", methods={"GET", "POST"}) */ @@ -227,18 +209,17 @@ class EntryController extends AppBaseController $propertyAccessor = PropertyAccess::createPropertyAccessor(); $parentBlock = $propertyAccessor->getValue($attributes, $blockId); - $form = $this->createForm(BlockType::class, null, [ + $form = $this->createForm($this->getBlockType($blockCategory), null, [ 'action' => $this->generateUrl('app_entry_add_block', [ 'id' => $entry->getId(), 'blockId' => $blockId, 'blockCategory' => $blockCategory, ]), - 'blockCategory' => $blockCategory, ]); $form->handleRequest($request); if ($form->isSubmitted() && $form->isValid()) { - $parentBlock[$blockCategory][] = $form->get('block')->getData(); + $parentBlock[$blockCategory][] = $form->getData(); $propertyAccessor->setValue($attributes, $blockId, $parentBlock); $entry->setAttributes($attributes); $this->em->flush(); @@ -252,6 +233,17 @@ class EntryController extends AppBaseController ]); } + public function getBlockType($blockCategory) + { + switch ($blockCategory) { + case Entry::ATTR_COMMENT: return CommentType::class; + case Entry::ATTR_EXAMPLE: return ExampleType::class; + case Entry::ATTR_DEFINITION: return DefinitionType::class; + case Entry::ATTR_PRONUNCIATION: return PronunciationType::class; + default: return BlockType::class; + } + } + /** * @Route("/{id}/add-block-pos", name="app_entry_add_block_pos", methods={"GET", "POST"}) */ @@ -290,4 +282,24 @@ class EntryController extends AppBaseController ]); } + /** + * @Route("/{id}/delete-block/{blockId}", name="app_entry_delete_block", methods={"GET", "POST"}) + */ + public function deleteBlock(Request $request, Entry $entry, $blockId): Response + { + $attributes = $entry->getAttributes(); + $propertyAccessor = PropertyAccess::createPropertyAccessor(); + preg_match("/(.*)\[([^]]+)\]$/", $blockId, $matches); + $parentId = $matches[1]; + $childId = $matches[2]; + $parentBlock = $propertyAccessor->getValue($attributes, $parentId); + + unset($parentBlock[$childId]); + $propertyAccessor->setValue($attributes, $parentId, $parentBlock); + $entry->setAttributes($attributes); + $this->em->flush(); + + return $this->redirectToRoute('app_entry_show', ['id' => $entry->getId()]); + } + } diff --git a/src/Controller/LabelController.php b/src/Controller/LabelController.php index 03db8522f25bacf4d738b29e7385b5075b4bc808..24de6014244aba592451f331bb17fc8c055faddc 100644 --- a/src/Controller/LabelController.php +++ b/src/Controller/LabelController.php @@ -294,6 +294,7 @@ class LabelController extends AppBaseController $this->getOrCreateEntryInZeroLexicon($headword); } $headword->addLabel($label); + $this->addFlash('success', "« " . $word . " » a été ajouté à Balex depuis le wiktionnaire"); $this->em->flush(); return $this->render('closeModalAndReload.html.twig'); diff --git a/src/Entity/Entry.php b/src/Entity/Entry.php index 743e4d61f006d2f3f31627b2eb1a80057918fef0..5442bfab67882384629ff792875e32f113d99c83 100644 --- a/src/Entity/Entry.php +++ b/src/Entity/Entry.php @@ -24,6 +24,7 @@ class Entry const ATTR_PRONUNCIATION = 'Pronunciations'; const ATTR_DEFINITION = 'Definitions'; const ATTR_COMMENT = 'Comments'; + const ATTR_EXAMPLE = 'Examples'; const PART_OF_SPEECH_LIST = [ "N" => "N", diff --git a/src/Form/BlockType.php b/src/Form/BlockType.php index b1294b1b6d9045814532ce948dec879450510666..94ceca7b5828b5fa63b36add3e0396fae2e7d1f9 100644 --- a/src/Form/BlockType.php +++ b/src/Form/BlockType.php @@ -35,34 +35,12 @@ class BlockType extends AbstractType { $user = $this->security->getUser(); - $blockCategory = $options['blockCategory']; - if ($blockCategory === Entry::ATTR_PRONUNCIATION) { - $builder - ->add('block', PronunciationType::class, [ - 'label' => false, - ]) - ; - } elseif ($blockCategory === Entry::ATTR_DEFINITION) { - $builder - ->add('block', DefinitionType::class, [ - 'label' => false, - ]) - ; - } elseif ($blockCategory === Entry::ATTR_COMMENT) { - $builder - ->add('block', CommentType::class, [ - 'label' => false, - 'user' => $user->getPseudo(), - ]) - ; - } else { $builder ->add('block', TextareaType::class, [ 'label' => false, ]) ; - } $builder @@ -79,7 +57,6 @@ class BlockType extends AbstractType 'data-ajax-form-target' => '#bootstrap-modal .modal-content', 'novalidate' => 'novalidate', ], - 'blockCategory' => null, ]); } } diff --git a/src/Form/CommentType.php b/src/Form/CommentType.php index b2e86751ffbecc671290ac97a4ef55f9e2dc1f88..5657d62cf265c44ac92f04a24b40a6788524be3f 100644 --- a/src/Form/CommentType.php +++ b/src/Form/CommentType.php @@ -18,31 +18,51 @@ use Symfony\Component\Form\Extension\Core\Type\TextareaType; use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Security\Core\Security; class CommentType extends AbstractType { + /** + * @var Security + */ + private $security; + + public function __construct(Security $security) + { + $this->security = $security; + } + public function buildForm(FormBuilderInterface $builder, array $options): void { + $user = $this->security->getUser(); $builder ->add('text', TextareaType::class, [ 'label' => "Commentaire", ]) ->add('user', HiddenType::class, [ 'label' => false, - 'data' => $options['user'], + 'data' => $user->getPseudo(), ]) ->add('date', HiddenType::class, [ 'label' => false, 'data' => (new \DateTime('now'))->format('d/m/Y - H:i'), ]) ; + $builder + ->add('submit', SubmitType::class, [ + 'label' => 'Enregistrer', + ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ + 'attr' => [ + 'data-ajax-form' => '', + 'data-ajax-form-target' => '#bootstrap-modal .modal-content', + 'novalidate' => 'novalidate', + ], 'user' => null, - 'date' => null, ]); } } diff --git a/src/Form/DefinitionType.php b/src/Form/DefinitionType.php index 2286a80c52988a4e919d80384654b2e648bd2012..9cddc3ea4cb07d6fe38270e6e542abbe251913d3 100644 --- a/src/Form/DefinitionType.php +++ b/src/Form/DefinitionType.php @@ -27,11 +27,20 @@ class DefinitionType extends AbstractType 'label' => "Définition", ]) ; + $builder + ->add('submit', SubmitType::class, [ + 'label' => 'Enregistrer', + ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ + 'attr' => [ + 'data-ajax-form' => '', + 'data-ajax-form-target' => '#bootstrap-modal .modal-content', + 'novalidate' => 'novalidate', + ], ]); } } diff --git a/src/Form/ExampleType.php b/src/Form/ExampleType.php new file mode 100644 index 0000000000000000000000000000000000000000..069c23c8015bc6bb25a8b7b31ad99878a15d6015 --- /dev/null +++ b/src/Form/ExampleType.php @@ -0,0 +1,46 @@ +<?php + +namespace App\Form; + +use App\Entity\Entry; +use App\Entity\Label; +use App\Entity\User; +use App\Languages\LanguagesIso; +use App\Repository\GroupRepository; +use Symfony\Bridge\Doctrine\Form\Type\EntityType; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Core\Type\ChoiceType; +use Symfony\Component\Form\Extension\Core\Type\DateTimeType; +use Symfony\Component\Form\Extension\Core\Type\DateType; +use Symfony\Component\Form\Extension\Core\Type\SubmitType; +use Symfony\Component\Form\Extension\Core\Type\TextareaType; +use Symfony\Component\Form\Extension\Core\Type\TextType; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\OptionsResolver\OptionsResolver; + +class ExampleType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options): void + { + $builder + ->add('example', TextareaType::class, [ + 'label' => "Exemple", + ]) + ; + $builder + ->add('submit', SubmitType::class, [ + 'label' => 'Enregistrer', + ]); + } + + public function configureOptions(OptionsResolver $resolver): void + { + $resolver->setDefaults([ + 'attr' => [ + 'data-ajax-form' => '', + 'data-ajax-form-target' => '#bootstrap-modal .modal-content', + 'novalidate' => 'novalidate', + ], + ]); + } +} diff --git a/src/Form/PronunciationType.php b/src/Form/PronunciationType.php index 747741549611290d1bc75fbd7d233717a377f1bc..c67092ebe6f8caa62bdf5ad9522617310bc613ce 100644 --- a/src/Form/PronunciationType.php +++ b/src/Form/PronunciationType.php @@ -31,11 +31,20 @@ class PronunciationType extends AbstractType 'label' => "Accent", ]) ; + $builder + ->add('submit', SubmitType::class, [ + 'label' => 'Enregistrer', + ]); } public function configureOptions(OptionsResolver $resolver): void { $resolver->setDefaults([ + 'attr' => [ + 'data-ajax-form' => '', + 'data-ajax-form-target' => '#bootstrap-modal .modal-content', + 'novalidate' => 'novalidate', + ], ]); } } diff --git a/src/Manager/WiktionaryManager.php b/src/Manager/WiktionaryManager.php index 77c7e63352a66f506fe0606c0b0108effe27ee33..9ebdf38610634e44a79b7c3c36218a3069fff804 100644 --- a/src/Manager/WiktionaryManager.php +++ b/src/Manager/WiktionaryManager.php @@ -162,7 +162,7 @@ class WiktionaryManager foreach (reset($wikSense)['exs'] as $wikExample) { $ex = $wikExample['example']; if ($ex) { - $examples[] = $ex; + $examples[] = $wikExample; } } if ($examples) { diff --git a/templates/entry/_entryAttributes.html.twig b/templates/entry/_entryAttributes.html.twig index 3bdb9edb7b3a11ee1836b7d413c144c3b0051fa2..c10b388242c0a8f2285f2e7ae11d65a0719078dc 100644 --- a/templates/entry/_entryAttributes.html.twig +++ b/templates/entry/_entryAttributes.html.twig @@ -1,5 +1,5 @@ <div id="entryAttributes" class="ps-5"> - {{ dump(entry.attributes) }} +{# {{ dump(entry.attributes) }}#} <h1> {{ entry }} @@ -55,18 +55,20 @@ {{ _self.comments(entry, definition, definitionKey) }} - {% for key, example in definition.Examples|default([]) %} - {### EXEMPLES ######### SET KEY ##########} - {% set exampleKey = definitionKey~'[Examples]['~key~']' %} + <div class="ms-3"> + {% for key, example in definition.Examples|default([]) %} + {### EXEMPLES ######### SET KEY ##########} + {% set exampleKey = definitionKey~'[Examples]['~key~']' %} - <p class="fst-italic"> - {{ example }} -{# {{ _self.actions(entry, exampleKey, ['comment'], "", 'Comments') }}#} - {{ _self.actions(entry, exampleKey, ['edit', 'delete']) }} - </p> + <p class="fst-italic"> + {{ example.example }} + {{ _self.actions(entry, exampleKey, ['comment'], "", 'Comments') }} + {{ _self.actions(entry, exampleKey, ['edit', 'delete'], "", 'Examples') }} + </p> -{# {{ _self.comments(entry, example, exampleKey) }}#} - {% endfor %} + {{ _self.comments(entry, example, exampleKey) }} + {% endfor %} + </div> </div> {% endfor %} @@ -84,7 +86,7 @@ <div class="comment-block"> {{ comment.text|nl2br }} <div class=" pt-2"> - <span class="fst-italic"> + <span class="fst-italic text-dark-grey"> {{ "Par"|trans }} {{ comment.user }} {{ "le"|trans }} {{ comment.date }} </span> {{ _self.actions(entry, commentKey, ['edit', 'delete'], '', 'Comments') }} diff --git a/templates/group/index.html.twig b/templates/group/index.html.twig index b4b3f11f5888c28f38beb295286b38f4001927f9..40bb738aeaf84c110bf19db33ccb92d8c9dc8629 100644 --- a/templates/group/index.html.twig +++ b/templates/group/index.html.twig @@ -34,13 +34,16 @@ <td>{{ group.admins|join(', ') }}</td> <td>{{ group.groupMemberships|length }}</td> <td class="text-end"> + + {% if is_granted('GROUP_DELETE', group) %} + <div class="d-inline-block">{{ include('group/_delete_form.html.twig') }}</div> + {% endif %} + {% if is_granted('GROUP_VIEW', group) %} <a href="{{ path('app_group_show', {'id': group.id}) }}" class="btn btn-dark btn-xs">Voir</a> {% endif %} {# <a href="{{ path('app_group_edit', {'id': group.id}) }}">edit</a>#} - {% if is_granted('GROUP_DELETE', group) %} - <div class="d-inline-block">{{ include('group/_delete_form.html.twig') }}</div> - {% endif %} + </td> </tr> {% else %} diff --git a/templates/home.html.twig b/templates/home.html.twig index 69857e9c64437185c5fb56494a1a340a94f06f33..93a7954fee36ac71b46609ff7175bc9395f26547 100644 --- a/templates/home.html.twig +++ b/templates/home.html.twig @@ -85,9 +85,11 @@ <h1 class="mt-5">{{ "Mot du jour"|trans }}</h1> <div class="card mt-3"> <div class="card-body bg-pink"> - <a href="{{ path('app_entry_show', {id: entry.id}) }}"> - {% include "entry/_entryAttributes.html.twig" %} - </a> + {% if entry %} + <a href="{{ path('app_entry_show', {id: entry.id}) }}"> + {% include "entry/_entryAttributes.html.twig" %} + </a> + {% endif %} </div> </div> </div> diff --git a/templates/label/_labelBadge.html.twig b/templates/label/_labelBadge.html.twig index a70ab0ecf44f74844346f773bf9748bbfbf9fde8..eb11758f2d2cf12e6b2bb2d7850a5f0b52a54f3f 100644 --- a/templates/label/_labelBadge.html.twig +++ b/templates/label/_labelBadge.html.twig @@ -1,4 +1,5 @@ -<div class="badge rounded-pill {{ label.isMilestone ? 'badge-milestone'}} position-relative text-black {{ label|labelClass }}" style="margin-right: 5px;" +<div class="badge rounded-pill {{ label.isMilestone ? 'badge-milestone'}} position-relative text-black {{ label|labelClass }} + {{ label.isMilestone or label.isInstitutional or label.isMasterPublic ? 'border-auto'}}" style="margin-right: 5px;" title="{{ label.description }}. Updated: {{ label.updatedAt|date('d/m/Y') }}"> {{ label }} {% if label.isMilestone %}<br>{{ label.getMilestone|date('d/m/Y') }}{% endif %} diff --git a/templates/label/show.html.twig b/templates/label/show.html.twig index 96bff2bf5da0a818c591ca6e63a14e2c118c9673..46d6ac45cac0a02a5a12a99ae72edb391635333a 100644 --- a/templates/label/show.html.twig +++ b/templates/label/show.html.twig @@ -26,7 +26,7 @@ </div> <div class="d-flex justify-content-start align-items-center mt-3"> - <h4>{{ label.description|nl2br|raw }}</h4> + <h4>{{ label.description|nl2br|raw ? : 'Add a description'|trans }}</h4> <a title="{{ 'Modifier la description'|trans }}" href="#" data-url="{{ path('app_label_edit_description', {id: label.id}) }}" class="modal-form ms-3 btn btn-dark btn-sm"><i class="fa fa-pencil"></i></a> </div> @@ -66,7 +66,7 @@ <th class="text-center"> <div class="d-flex justify-content-around align-items-center"> <span>{{ "Mots-vedettes"|trans }}</span> - <a title="{{ "Ajouter"|trans }}" href="#" data-url="{{ path('app_label_add_headword', {id: label.id}) }}" class="modal-form btn btn-dark btn-sm"><i class="fa fa-plus"></i></a> + <a title="{{ "Ajouter"|trans }}" href="#" data-url="{{ path('app_label_add_headword', {id: label.id}) }}" class="ms-2 modal-form"><i class="fa fa-plus-circle text-success"></i></a> </th> <th colspan="{{ lexiconsNb }}" class="text-center">{{ "Présence des mots dans les lexiques"|trans }}</th> </tr> @@ -87,7 +87,7 @@ {% set labelVisibleInLexicon = label_manager.isVisible(label, lexicon, app.user) %} <th class="text-center {{ labelVisibleInLexicon ? 'bg-green' : 'faded bg-grey' }}"> <a href="{{ path('app_label_toggle_visibility', {id: label.id, lexiconId: lexicon.id, backUrl: app.request.uri}) }}" class="overlay-on-click"> - {{ lexicon|badge((labelVisibleInLexicon ? 'Masquer le label dans ce lexique' : 'Montrer le label dans ce lexique')|trans) }} + {{ lexicon|badge((labelVisibleInLexicon ? 'Label visible dans ce lexique, cliquer pour le masquer' : 'Label non visible dans ce lexique, cliquer pour le montrer')|trans) }} </a> </th> {% endfor %}