Skip to content
Snippets Groups Projects
Commit 1363bae0 authored by Pierre Fleutot's avatar Pierre Fleutot
Browse files

Page Entrée : fin création nouveau mot. Début Barre de recherche headword dans la navbar

parent dd64950b
No related branches found
No related tags found
No related merge requests found
......@@ -200,15 +200,23 @@ table.label-table > tbody > tr > td {
}
.nav-tabs .nav-link {
color: black;
border-bottom: 0;
}
.nav-tabs a.nav-link.active {
font-weight: bold;
}
.nav-tabs a.nav-link.active, .nav-tabs a.nav-link.active:hover, .nav-tabs a.nav-link.active:focus {
border-color: #767676;
border-bottom-color: transparent;
}
.nav-tabs, .nav-tabs a.nav-link {
border-bottom: 1px solid #767676;
}
#tabContent {
background-color: #FDF6F6;
padding: 15px;
border: 1px solid #767676;;
border-top-color: transparent;
padding: 30px;
}
#tabContent.tab-wiktionnary {
background-color: #FFE4E4;
......@@ -216,4 +224,8 @@ table.label-table > tbody > tr > td {
#tableLabels.table > tbody > tr > td {
height: 52px;
}
#tabContent #tableLabels {
background-color: white;
}
\ No newline at end of file
......@@ -12,6 +12,7 @@ $(function() {
initializeForm();
initializeAjaxLinks();
initializeSearchHeadwords();
// Pour améliorer en spécifiant la méthode (DELETE, POST...) Voir https://stackoverflow.com/a/8983053/4954580
initializeFormToggles();
initializeConfirmDialog(); // Confirmation des suppressions dans une modal Boostrap
......@@ -42,7 +43,7 @@ $(function() {
var isForm = $(e.currentTarget).hasClass('modal-form');
var extraFormId = $(e.currentTarget).data('extra-form-id');
if ($(extraFormId)) {
if (extraFormId && $(extraFormId)) {
url = url + (url.indexOf('?') >= 0 ? '&' : '?') + $(extraFormId).serialize();
};
......@@ -89,20 +90,6 @@ $(function() {
$(':submit', $form).button('reset');
initializeForm(true);
//$('#bootstrap-modal').scrollTop(0); // pour voir les erreurs de formulaire sur un long formulaire
},
error: function() { // exécuté quand le serveur a rencontré une erreur
$(':submit', $form).button('reset');
BootstrapDialog.show({
type: BootstrapDialog.TYPE_WARNING,
title: "Erreur",
message: "Un problème est survenu. Il est possible que vos données n'aient pas été enregistrées.",
buttons: [{
label: 'Fermer',
action: function(dialogRef){
dialogRef.close();
}
}]
});
}
});
});
......@@ -383,4 +370,32 @@ function initializeAjaxLinks() {
}
})
function initializeSearchHeadwords() {
// cliqk sur search => ajax pour get url entry_show dan sle bon lexique
$form = $('#searchHeadwordsForm');
$form.on('submit', function (e) {
e.preventDefault();
var $overlay = $('#overlay').show();
var search = $('#searchHeadwordBox').val();
$.ajax({
type: 'GET',
url: $form.attr('action') + '?' + search,
dataType: "json",
success: function (response, textStatus, xhr) {
window.location.href = response;
},
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR.responseText, textStatus, errorThrown);
$wordCreationConfirmationLink = $('headwordConfirmCreation');
$wordCreationConfirmationLink.data('url', $wordCreationConfirmationLink.data('url') + '?' + search);
$wordCreationConfirmationLink.click();
// $overlay.hide();
}
})
});
// si pas présnete => modal-form ou confirm-dialog pour demander création dans Agora
}
}
\ No newline at end of file
......@@ -10,6 +10,7 @@ use App\Entity\Label;
use App\Entity\Lexicon;
use App\Entity\User;
use App\Languages\LanguagesIso;
use App\Manager\LexiconManager;
use App\Manager\WiktionaryManager;
use Doctrine\ORM\EntityManager;
use Doctrine\Persistence\ManagerRegistry;
......@@ -185,6 +186,15 @@ class AppBaseController extends AbstractController
return LanguagesIso::getCodes();
}
//si un user a la possibilité de travailler avec 2 langues, il faudra stocker la langue utilisée en session.
// Certaines actions ont besoin de la langue (ajouter un mot-vedette à un label par ex, car le label n’est pas lié à une langue).
// Pour l’instant on retourne la première langue étudiée par l’user
// (qu'on utilise également pour déterminer la langue de son lexique perso lors de la création de l'utilisateur)
public function getLanguage()
{
return $this->getUser()->getFirstStudiedLanguage();
}
/**
* - Si on trouve un headword dont la valeur est word, on le retourne
* - Sinon, si on trouve une graphie dont la valeur est word, on retourne le premier headword lié à cette graphie s'il existe.
......@@ -217,6 +227,15 @@ class AppBaseController extends AbstractController
return $this->doctrine->getRepository(Lexicon::class)->findOneBy(['language' => $language, 'category' => Lexicon::TYPE_ZERO]);
}
/**
* @param $language
* @return Lexicon|null
*/
public function getNewWordsLexicon($language)
{
return $this->doctrine->getRepository(Lexicon::class)->findOneBy(['language' => $language, 'category' => Lexicon::TYPE_NEW_WORDS]);
}
/**
*
* On crée la graphie dans Balex si elle n'existe pas, on crée un headword
......@@ -376,14 +395,46 @@ class AppBaseController extends AbstractController
if ($zeroEntry) {
$entry->setAttributes($zeroEntry->getAttributes());
} else {
$baseEntrySchema = json_decode(file_get_contents(__DIR__ . "/../JsonSchema/baseEntrySchema.json"), true);
$baseEntrySchema['Headword'] = $headword->getValue();
$entry->setAttributes($baseEntrySchema);
$this->initializeWithBasicAttributes($entry);
}
return $entry;
}
/**
* On initialise l'entrée passée en paramètre avec une structure minimale presque vide
*
* @param Entry $entry
*/
public function initializeWithBasicAttributes(Entry $entry)
{
$headword = $entry->getHeadword();
$baseEntrySchema = json_decode(file_get_contents(__DIR__ . "/../JsonSchema/baseEntrySchema.json"), true);
$baseEntrySchema['Headword'] = $headword->getValue();
$entry->setAttributes($baseEntrySchema);
}
/**
* On crée l'entrée dans le lexique de proposition des nouveaux mots
* On initialise avec des infos minimales
*
* @param Headword $headword
* @return Entry
* @throws \Exception
*/
public function createEntryInNewWordsLexicon(Headword $headword)
{
$newWordsLexicon = $this->em->getRepository(Lexicon::class)->findOneBy(['language' => $headword->getLanguage(), 'category' => Lexicon::TYPE_NEW_WORDS]);
$entry = new Entry();
$this->em->persist($entry);
$entry->setHeadword($headword);
$entry->setLanguage($headword->getLanguage());
$entry->setLexicon($newWordsLexicon);
$this->initializeWithBasicAttributes($entry);
return $entry;
}
/**
* @param Request $request
* @param $sortingColumn
......
......@@ -35,22 +35,37 @@ class HeadwordController extends AppBaseController
// 'headwords' => $headwordRepository->findAll(),
// ]);
// }
//
// /**
// * @Route("/{id}", name="app_headword_show", methods={"GET"})
// */
// public function show(Request $request, Headword $headword): Response
// {
// $form = $this->createForm(SearchStringType::class,null, array('method' => 'GET'));
// $form->handleRequest($request);
// if ($form->get('searchString')->getData()) {
//// TODO $labelManager->setSearchString($form->get('searchString')->getData());
// }
// return $this->render('headword/show.html.twig', [
// 'headword' => $headword,
// 'form' => $form->createView(),
// ]);
// }
/**
* @Route("/search", name="app_headword_search")
*/
public function search(Request $request): Response
{
$search = $request->get('search');
$orderedLexicons = array_merge($this->getUser()->getMyLexicons(), [
$this->getZeroLexicon($this->getLanguage()),
$this->getNewWordsLexicon($this->getLanguage()),
]);
$entries = $this->em->getRepository(Entry::class)->getByHeadwordValueInLexicons($search, $orderedLexicons);
if ($entries) {
return new JsonResponse($this->generateUrl('app_entry_show', ['id' => $entries[0]->getId()]));
} else {
return new JsonResponse(null,404);
}
}
/**
* @Route("/confirm-new-word-creation", name="app_headword_confirm_creation")
*/
public function confirmNewWordCreation(Request $request): Response
{
return $this->render("genericModalForm.html.twig", [
'form' => $form->crea
]);
}
/**
* @Route("/{id}/toggle-known-headword/{userId}", name="app_headword_toggle_known", methods={"GET"})
......
......@@ -11,10 +11,12 @@ use App\Entity\Lexicon;
use App\Entity\Log;
use App\Form\CopyEntriesType;
use App\Form\CopyHeadwordsType;
use App\Form\EnterWordType;
use App\Form\LabelDescriptionType;
use App\Form\LabelType;
use App\Form\SearchStringType;
use App\Manager\LabelManager;
use App\Manager\WiktionaryManager;
use App\Repository\HeadwordRepository;
use App\Repository\LabelRepository;
use Doctrine\Persistence\ManagerRegistry;
......@@ -256,22 +258,52 @@ class LabelController extends AppBaseController
* @Route("/{id}/add-headword", name="app_label_add_headword", methods={"GET", "POST"})
*/
// * @IsGranted("LABEL_EDIT", subject="label")
public function addHeadwordDescription(Request $request, Label $label): Response
public function addHeadwordDescription(WiktionaryManager $wiktionaryManager, Request $request, Label $label): Response
{
$form = $this->createForm(LabelDescriptionType::class, $label, [
$displayForceValidation = false;
$form = $this->createForm(EnterWordType::class, null, [
'action' => $this->generateUrl('app_label_add_headword', ['id' => $label->getId()])
]);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$labelRepository->add($label, true);
$word = $form->get('word')->getData();
// On regarde si le mot-vedette existe
$headword = $this->em->getRepository(Headword::class)->findOneBy([
'value' => $word,
'language' => $this->getLanguage(),
]);
// si c'est le cas on lui ajoute le label
if ($headword) {
$headword->addLabel($label);
$this->em->flush();
return $this->render('closeModalAndReload.html.twig');
return $this->render('closeModalAndReload.html.twig');
} else {
// Sinon on essaie de créer le mot-vedette à partir du Wiktionnaire
if ($form->get('forceValidation')->isClicked() || $wiktionaryManager->search($word, $this->getLanguage())) {
$headword = $this->newHeadword($word, $this->getLanguage());
if ($form->get('forceValidation')->isClicked()) {
$this->createEntryInNewWordsLexicon($headword);
} else {
$this->getOrCreateEntryInZeroLexicon($headword);
}
$headword->addLabel($label);
$this->em->flush();
return $this->render('closeModalAndReload.html.twig');
} else {
$displayForceValidation = true;
$this->addFlash('warning', sprintf("Le mot «%s» n'existe ni dans Balex ni dans le wiktionnaire. Voulez-vous le proposer dans l'Agora des nouveaux mots ?", $word));
}
}
}
return $this->render('genericModalForm.html.twig', [
return $this->render('label/addHeadwordToLabel.html.twig', [
'title' => "Modifier le label",
'form' => $form->createView(),
'displayForceValidation' => $displayForceValidation,
]);
}
......
......@@ -23,21 +23,23 @@ class EnterWordType extends AbstractType
{
$builder
->add('description', TextareaType::class, [
'label' => 'Description',
->add('word', TextType::class, [
'label' => 'Mot',
])
;
$builder
->add('forceValidation', SubmitType::class, [
'label' => 'Confirmer',
])
->add('submit', SubmitType::class, [
'label' => 'Enregistrer',
'label' => 'Valider',
]);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => Label::class,
'attr' => [
'data-ajax-form' => '',
'data-ajax-form-target' => '#bootstrap-modal .modal-content',
......
......@@ -58,6 +58,21 @@ class EntryRepository extends ServiceEntityRepository
}
public function getByHeadwordValueInLexicons($value, $lexicons)
{
$qb = $this->createQueryBuilder('e')
->leftJoin('e.headword', 'h')
->leftJoin('e.lexicon', 'lex')
->andWhere('e.lexicon IN (:lexicons)')
->setParameter('lexicons', $lexicons)
->andWhere('h.value = :value')
->setParameter('value', $value)
;
return $qb->getQuery()->getResult();
}
public function add(Entry $entity, bool $flush = false): void
{
$this->getEntityManager()->persist($entity);
......
......@@ -56,8 +56,10 @@
{% endfor %}
{% if not entry.lexicon.isNewWords %}
{% set zeroLexicon = lexicon_manager.zeroLexicon(entry.language) %}
{% set entryZero = zeroLexicon.getEntryForHeadword(entry.headword) %}
<li class="nav-item">
<a class="nav-link tab-dark-pink" href="#">{{ "Wiktionnaire"|trans }}</a>
<a class="nav-link {{ zeroLexicon == entry.lexicon ? 'active' }} tab-dark-pink" href="{{ path('app_entry_show', {id: entryZero.id}) }}">{{ "Wiktionnaire"|trans }}</a>
</li>
{% endif %}
</ul>
......
{% extends 'modal.html.twig' %}
{% block modal_title %}
{{ "Ajouter un mot-vedette à ce label"|trans }}
{% endblock %}
{% block modal_body %}
<div class="row">
<div class="col-md-12">
{% include "flashes.html.twig" %}
{{ form_start(form) }}
{{ form_errors(form) }}
{% for child in form %}
{% if child.vars.name not in ['submit', 'forceValidation'] %}
{{ form_row(child) }}
{% endif %}
{% endfor %}
<div class="row pt-3">
<div class="col-sm-4"></div>
<div class="col-sm-8">
{% if displayForceValidation %}
{{ form_widget(form.forceValidation) }}
{% else %}
{{ form_widget(form.submit) }}
{% endif %}
<button type="button" class="btn btn-light" data-bs-dismiss="modal">{{ 'Annuler'|trans }}</button>
</div>
</div>
{{ form_end(form, {render_rest: false}) }}
</div>
</div>
{% endblock %}
\ No newline at end of file
......@@ -9,6 +9,10 @@
<div class="row my-5">
<div class="col-md-12">
<h1 class="my-3">
<i class="fa fa-tag"></i> {{ "Labels"|trans }}
</h1>
<div class="row">
<div class="col-md-6">
......@@ -62,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="#" actionUrl="{{ 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="modal-form btn btn-dark btn-sm"><i class="fa fa-plus"></i></a>
</th>
<th colspan="{{ lexiconsNb }}" class="text-center">{{ "Présence des mots dans les lexiques"|trans }}</th>
</tr>
......@@ -92,6 +96,8 @@
<tbody>
{% for headword in headwords %}
{% set zeroLexicon = lexicon_manager.zeroLexicon(headword.language) %}
{% set entryZero = zeroLexicon.getEntryForHeadword(headword) %}
{# @var headword \App\Entity\Headword #}
<tr>
{# <td>{{entry.addingOrder }}</td>#}
......@@ -99,7 +105,7 @@
{# "value" est utilisé par Symfo quand on soumet le form. "data-headword-id" est utilisé par la vue chooseLabel pour injecter du json dans le sliens ajax #}
<input class="me-2" type="checkbox" name="form[selected_headwords][]"
value="{{ headword.id }}" id="form_selected_headwords_{{ headword.id }}"/>
<a href="{{ path('app_wiktionnary_show', {id: headword.id}) }}">
<a href="{{ path('app_entry_show', {id: entryZero.id}) }}">
{{ headword.value }}
</a>
</td>
......
......@@ -6,41 +6,52 @@
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<form class="d-flex" role="search">
<input class="form-control me-2" type="search" placeholder="{{ "Rechercher"|trans }}" aria-label="Search">
<form id="searchHeadwordsForm" class="d-flex" role="search" action="{{ path('app_headword_search') }}">
<input name="searchHeadwordBox" class="form-control me-2" type="search" placeholder="{{ "Rechercher"|trans }}" aria-label="Search">
<button class="btn btn-light me-3" type="submit"><i class="fa fa-search"></i> </button>
<a id="headwordConfirmCreation" href="#" class="modal-form d-none" data-url="{{ path('app_headword_confirm_creation') }}"></a>
</form>
{% if app.user %}
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link {{ 'app_group' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_group_index') }}"><i class="fa fa-users"></i> Groupes</a>
</li>
<li class="nav-item">
<a class="nav-link {{ 'app_friend' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_friend_index') }}"><i class="bi bi-person-heart"></i> Amis</a>
</li>
<li class="nav-item">
<a class="nav-link {{ 'app_label' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_label_index') }}"><i class="bi bi-tags"></i> Labels</a>
<a class="nav-link {{ 'app_label' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_label_index') }}">
<i class="bi bi-tags"></i> {{ "Labels"|trans }}</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle {{ 'app_lexicon' in app.request.attributes.get('_route') ? 'active' }}" data-bs-toggle="dropdown" href="#"><i class="bi bi-journals"></i> Lexiques</a>
<a class="nav-link dropdown-toggle {{ 'app_lexicon' in app.request.attributes.get('_route') ? 'active' }}" data-bs-toggle="dropdown" href="#">
<i class="bi bi-journals"></i> {{ "Lexiques"|trans }}</a>
<ul class="dropdown-menu">
{% for lexicon in app.user.myLexicons %}
<li><a class="dropdown-item" href="{{ path('app_lexicon_show', {id: lexicon.id}) }}">{{ lexicon }}</a></li>
{% endfor %}
</ul>
</li>
<li class="nav-item">
<a class="nav-link {{ 'app_group' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_group_index') }}">
<i class="fa fa-users"></i> {{ "Groupes"|trans }}</a>
</li>
<li class="nav-item">
<a class="nav-link {{ 'app_friend' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_friend_index') }}">
<i class="bi bi-person-heart"></i> {{ "Amis"|trans }}</a>
</li>
<li class="nav-item">
<a class="nav-link {{ 'app_dashboard' in app.request.attributes.get('_route') ? 'active' }}" href="#">
<i class="bi bi-speedometer"></i> {{ "Dashboard"|trans }}</a>
</li>
{% if is_granted('ROLE_ADMIN') %}
<li class="nav-item">
<a class="nav-link {{ 'app_user' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_user_index') }}"><i class="bi bi-person"></i> Utilisateurs</a>
<a class="nav-link {{ 'app_user' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_user_index') }}">
<i class="bi bi-person"></i> {{ "Utilisateurs"|trans }}</a>
</li>
{# <li class="nav-item">#}
{# <a class="nav-link {{ 'app_lexicon' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_lexicon_index') }}"><i class="bi bi-card-list"></i> Lexiques</a>#}
{# </li>#}
<li class="nav-item">
<a class="nav-link {{ 'app_client' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_client_index') }}"><i class="bi bi-window"></i> Applis clientes</a>
<a class="nav-link {{ 'app_client' in app.request.attributes.get('_route') ? 'active' }}" href="{{ path('app_client_index') }}">
<i class="bi bi-window"></i> {{ "Applis clientes"|trans }}</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ path('app.swagger_ui') }}"><i class="bi bi-terminal"></i> Swagger</a>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment