Implementing working filters (almost)

This commit is contained in:
Florian SYLVAIN
2022-01-05 12:02:20 +01:00
parent f55f866476
commit 183d53b8df
7 changed files with 86 additions and 56 deletions
+8 -7
View File
@@ -2,15 +2,16 @@
require_once("class/dump.php"); require_once("class/dump.php");
if (!isset($_GET['q']) || !isset($_GET['author'])) { if (!isset($_GET['q']) || !isset($_GET['search']) || !isset($_GET['option'])) {
print_r(json_encode(array("status" => 400, "message" => "Missing query type or attributes."))); print_r(json_encode(array("status" => 400, "message" => "Missing query type or attributes.")));
exit(); exit();
} }
$author_name = filter_var($_GET['author'], FILTER_SANITIZE_ADD_SLASHES);
$q = $_GET['q']; $q = $_GET['q'];
$search = filter_var($_GET['search'], FILTER_SANITIZE_ADD_SLASHES);
$option = $_GET['option'];
if (strlen($author_name) < 3) { if (strlen($search) < 3) {
print_r(json_encode(array( print_r(json_encode(array(
"status" => 400, "status" => 400,
"message" => "La recherche doit comporter un minimum de 3 caractères." "message" => "La recherche doit comporter un minimum de 3 caractères."
@@ -19,15 +20,15 @@ if (strlen($author_name) < 3) {
} }
$json_object = match ($q) { $json_object = match ($q) {
"theses" => dump::getTheseByAuthor($author_name), "theses" => dump::getTheses($search, $option),
"authors" => dump::getAuthorsByAuthor($author_name), "suggestion" => dump::getSuggestions($search, $option),
"authorsCount" => dump::getAuthorsCountByAuthor($author_name),
default => NULL, default => NULL,
}; };
$json = json_encode(array( $json = json_encode(array(
"status" => 200, "status" => 200,
"message" => "Success", "data" => $json_object "message" => "Success",
"data" => $json_object,
)); ));
echo $json; echo $json;
+41 -16
View File
@@ -23,6 +23,7 @@ let pagesNumbersContainer = document.querySelector('.page-nav')
let pagesNumbers = document.querySelector('.page-nav div') let pagesNumbers = document.querySelector('.page-nav div')
let resultsDiv = document.querySelector('#results') let resultsDiv = document.querySelector('#results')
let resultsCount = document.querySelector('#results-count') let resultsCount = document.querySelector('#results-count')
let filters = document.querySelectorAll('.filters p')
function sanitize(chain) { function sanitize(chain) {
return chain.replace(/[^a-zA-Z0-9\- ]/g,'') return chain.replace(/[^a-zA-Z0-9\- ]/g,'')
@@ -54,18 +55,19 @@ function emptyResults(withCount = false) {
resultsCount.innerHTML = "" resultsCount.innerHTML = ""
} }
let authorName = ""; let searchString = "";
let lastRequest = null let lastRequest = null
let queryOption = null
function apiRequestThese(author) { function apiRequestThese(search) {
hideSuggestions() hideSuggestions()
if (lastRequest === null || (new Date().getTime() - lastRequest) > 1000) { if (lastRequest === null || (new Date().getTime() - lastRequest) > 1000) {
lastRequest = new Date().getTime() lastRequest = new Date().getTime()
emptyResults(true) emptyResults(true)
pagesNumbers.innerHTML = "" pagesNumbers.innerHTML = ""
loader.style.display = "block" loader.style.display = "block"
authorName = sanitize(author) searchString = sanitize(search)
fetch(`api.php?q=theses&author=${author}`) fetch(`api.php?q=theses&search=${search}&option=${queryOption}`)
.then(response => response.json()) .then(response => response.json())
.then(data => displayResults(data)) .then(data => displayResults(data))
} else { } else {
@@ -139,7 +141,7 @@ function displayResults(results) {
let qAuthor = elem[0] let qAuthor = elem[0]
let author = document.createElement('h3') let author = document.createElement('h3')
let pre_replacement = new RegExp( authorName, 'gi').exec(qAuthor) let pre_replacement = new RegExp(searchString, 'gi').exec(qAuthor)
author.innerHTML = qAuthor.replace(pre_replacement, `<mark>${pre_replacement}</mark>`) author.innerHTML = qAuthor.replace(pre_replacement, `<mark>${pre_replacement}</mark>`)
let qTitle = elem[2] let qTitle = elem[2]
@@ -168,14 +170,14 @@ function displayResults(results) {
elem.forEach(e => { elem.forEach(e => {
if (i > 3 && i !== 14) { if (i > 3 && i !== 14) {
let child = document.createElement('p') let child = document.createElement('p')
let pre_replacement = new RegExp(authorName, 'gi').exec(e) let pre_replacement = new RegExp(searchString, 'gi').exec(e)
child.innerHTML = e.replace(pre_replacement, `<mark>${pre_replacement}</mark>`) child.innerHTML = e.replace(pre_replacement, `<mark>${pre_replacement}</mark>`)
content.appendChild(child) content.appendChild(child)
} i += 1 } i += 1
}) })
count += 1 count += 1
header.addEventListener('click', (e) => { header.addEventListener('click', () => {
focusResults(result) focusResults(result)
}) })
@@ -185,7 +187,7 @@ function displayResults(results) {
}) })
let nb = document.createElement("p") let nb = document.createElement("p")
nb.innerHTML = `Nombre de résultats pour "${authorName}": nb.innerHTML = `Nombre de résultats pour "${searchString}":
${new Intl.NumberFormat('fr-FR', { maximumSignificantDigits: 3 }).format(count)}.` ${new Intl.NumberFormat('fr-FR', { maximumSignificantDigits: 3 }).format(count)}.`
resultsCount.appendChild(nb) resultsCount.appendChild(nb)
@@ -216,6 +218,7 @@ function displayResults(results) {
let currentPage = 1 let currentPage = 1
// TODO URGENCE ABSOLUE Charger les résultats de 10 à 10 pour de vrai depuis la requête SQL elle-même (bon courage)
function browseResults(wantedPage) { function browseResults(wantedPage) {
if ((wantedPage > 0 && wantedPage < nbPages + 1)) { if ((wantedPage > 0 && wantedPage < nbPages + 1)) {
emptyResults() emptyResults()
@@ -239,7 +242,7 @@ function realTimeDisplay() {
if (search.length > 3 && (search !== lastSearch && (new Date().getTime() - lastSuggestion) > 500)) { if (search.length > 3 && (search !== lastSearch && (new Date().getTime() - lastSuggestion) > 500)) {
lastSearch = search lastSearch = search
lastSuggestion = new Date().getTime() lastSuggestion = new Date().getTime()
fetch(`api.php?q=authors&author=${search}`) fetch(`api.php?q=suggestion&search=${search}&option=${queryOption}`)
.then(response => response.json()) .then(response => response.json())
.then(results => { .then(results => {
suggestions.innerHTML = "" suggestions.innerHTML = ""
@@ -282,6 +285,20 @@ function switchNavTitle(q) {
} }
} }
function updateFilter(f) {
if (f.includes('f-')) {
queryOption = f.substring(2)
} else {
queryOption = f
}
filters.forEach(elem => {
elem.style.boxShadow = 'none'
})
document.querySelector('#f-' + queryOption).style.boxShadow = 'inset rgba(0, 0, 0, 0.40) 0 0 5px'
}
document.addEventListener('click', e => { document.addEventListener('click', e => {
if (e.target.id !== 'suggestions' && e.target !== searchBar && e.target !== searchBarButton) { if (e.target.id !== 'suggestions' && e.target !== searchBar && e.target !== searchBarButton) {
@@ -295,24 +312,32 @@ document.addEventListener('click', e => {
switchHam(true) switchHam(true)
} }
if (e.target === errorButton) { if (e.target === errorButton || e.target === errorButton.firstElementChild) {
error.classList.replace('fade-in', 'fade-out') error.classList.replace('fade-in', 'fade-out')
} }
let toggleSwitch = null let toggleSwitch = null
let toggleSwitchParent = null
if (e.target.classList.contains('slider')) { if (e.target.classList.contains('slider')) {
toggleSwitch = e.target toggleSwitch = e.target
toggleSwitchParent = e.target.parentNode
} else if (e.target.classList.contains('toggle-switch')) { } else if (e.target.classList.contains('toggle-switch')) {
toggleSwitch = e.target.firstElementChild toggleSwitch = e.target.firstElementChild
toggleSwitchParent = e.target
} }
if (toggleSwitch !== null) { if (toggleSwitch !== null) {
if (toggleSwitch.classList.contains('untoggle')) { if (toggleSwitch.classList.contains('untoggle')) {
toggleSwitchParent.style.backgroundColor = '#FFF'
toggleSwitch.classList.replace('untoggle', 'toggle') toggleSwitch.classList.replace('untoggle', 'toggle')
} else { } else {
toggleSwitchParent.style.backgroundColor = '#ECECEC'
toggleSwitch.classList.replace('toggle', 'untoggle') toggleSwitch.classList.replace('toggle', 'untoggle')
} }
} }
if (e.target.id.toString().includes('f-')) {
updateFilter(e.target.id)
}
} }
}) })
@@ -320,14 +345,14 @@ searchBar.addEventListener('focus', () => {
switchNavTitle(false) switchNavTitle(false)
}) })
// navbarForm.addEventListener('submit', e => { navbarForm.addEventListener('submit', () => {
// e.preventDefault() navbarForm.querySelector('input[name="option"]').value = queryOption
// let data = new FormData(navbarForm) })
// searchBar.blur()
// apiRequestThese(data.get('author'))
// })
let urlSearch = urlParams.get('search') let urlSearch = urlParams.get('search')
let urlOption = urlParams.get('option')
updateFilter(urlOption ? urlOption : 'f-auto')
if (urlSearch) { if (urlSearch) {
searchBar.value = urlSearch searchBar.value = urlSearch
-1
View File
@@ -1,6 +1,5 @@
<?php <?php
// Since I don't know atm if I am allowed to use external libs like dotenv, I used this piece of code to load .env file.
// Link : https://dev.to/fadymr/php-create-your-own-php-dotenv-3k2i // Link : https://dev.to/fadymr/php-create-your-own-php-dotenv-3k2i
// Author : F.R Michel // Author : F.R Michel
class dotEnv class dotEnv
+23 -25
View File
@@ -16,16 +16,31 @@ class dump {
return date("Y-m-d", strtotime($old_date)); return date("Y-m-d", strtotime($old_date));
} }
public static function getTheseByAuthor($author) : array { public static function getTheses(string $search, string $option) : array {
$theses_array = []; $theses_array = [];
$pdo_obj = new conf(); $pdo_obj = new conf();
$pdo = $pdo_obj->getPDO(); $pdo = $pdo_obj->getPDO();
$author = '%' . $author . '%'; $search = '%' . $search . '%';
$stmt = $pdo->prepare("SELECT * FROM theses WHERE author LIKE :author ORDER BY author;"); $stmt = match ($option) {
$stmt->bindParam(':author', $author, PDO::PARAM_STR, 100); 'auto' => $pdo->prepare("
SELECT *
FROM theses
WHERE author LIKE :search
OR title LIKE :search
OR these_director LIKE :search
OR soutenance_establishment LIKE :search;
"),
'author' => $pdo->prepare("SELECT * FROM theses WHERE author LIKE :search ORDER BY author;"),
'title' => $pdo->prepare("SELECT * FROM theses WHERE title LIKE :search;"),
'director' => $pdo->prepare("SELECT * FROM theses WHERE these_director LIKE :search;"),
'establishment' => $pdo->prepare("SELECT * FROM theses WHERE soutenance_establishment LIKE :search;"),
default => "",
};
$stmt->bindParam(':search', $search, PDO::PARAM_STR, 100);
$stmt->execute(); $stmt->execute();
$i = 0; $i = 0;
@@ -40,16 +55,16 @@ class dump {
return $theses_array; return $theses_array;
} }
public static function getAuthorsByAuthor(string $author_name) : array { public static function getSuggestions(string $search, string $option) : array {
$array = []; $array = [];
$author_name = '%' . $author_name . '%'; $search = '%' . $search . '%';
$pdo_obj = new conf(); $pdo_obj = new conf();
$pdo = $pdo_obj->getPDO(); $pdo = $pdo_obj->getPDO();
$stmt = $pdo->prepare("SELECT DISTINCT author FROM theses WHERE author LIKE :author_name LIMIT 10;"); $stmt = $pdo->prepare("SELECT DISTINCT author FROM theses WHERE author LIKE :search LIMIT 10;");
$stmt->bindParam(':author_name', $author_name, PDO::PARAM_STR, 100); $stmt->bindParam(':search', $search, PDO::PARAM_STR, 100);
$stmt->execute(); $stmt->execute();
while ($obj = $stmt->fetchObject()) { while ($obj = $stmt->fetchObject()) {
@@ -61,23 +76,6 @@ class dump {
return $array; return $array;
} }
public static function getAuthorsCountByAuthor(string $author_name) : int {
$author_name = '%' . $author_name . '%';
$pdo_obj = new conf();
$pdo = $pdo_obj->getPDO();
$stmt = $pdo->prepare("SELECT COUNT(author) FROM theses WHERE author LIKE :author_name;");
$stmt->bindParam(':author_name', $author_name, PDO::PARAM_STR, 100);
$stmt->execute();
while ($obj = $stmt->fetchObject()) {
foreach ($obj as $elem) {
return $elem;
}
} return 0;
}
public function sendThese($pdo) { public function sendThese($pdo) {
$data = [ $data = [
'author' => $this->these->getAuthor(), 'author' => $this->these->getAuthor(),
+2
View File
@@ -48,6 +48,8 @@
</svg> </svg>
</div> </div>
<!-- TODO Footer avec lien vers depot github -->
<script src="app.js"></script> <script src="app.js"></script>
</body> </body>
+5 -4
View File
@@ -12,6 +12,7 @@
<div class="research-section"> <div class="research-section">
<form class="navbar-form" method="GET" action="index.php"> <form class="navbar-form" method="GET" action="index.php">
<input type="text" name="search" placeholder="recherche" onkeyup="realTimeDisplay()" id="searchbar"> <input type="text" name="search" placeholder="recherche" onkeyup="realTimeDisplay()" id="searchbar">
<input style="display:none" type="text" name="option">
<button id="form-button"> <button id="form-button">
<img src="assets/search.svg" alt="search" id="search-button" class="animation-in"> <img src="assets/search.svg" alt="search" id="search-button" class="animation-in">
</button> </button>
@@ -26,10 +27,10 @@
<div> <div>
<h3>Filtres : </h3> <h3>Filtres : </h3>
<div class="filters"> <div class="filters">
<p>Auto</p> <p id="f-auto">Auto</p>
<p>Auteur</p> <p id="f-author">Auteur</p>
<p>Titre</p> <p id="f-director">Directeur</p>
<p>Date</p> <p id="f-establishment">Etablissement</p>
</div> </div>
</div> </div>
+6 -2
View File
@@ -178,12 +178,14 @@ header {
.filters { .filters {
display: flex; display: flex;
flex-wrap: wrap;
gap: 5px; gap: 5px;
color: white; color: white;
font-family: sans-serif; font-family: sans-serif;
} }
.filters p { .filters p {
margin: 0;
padding: 3px 10px 3px 10px; padding: 3px 10px 3px 10px;
border-radius: 10px; border-radius: 10px;
background-color: #39B4E7; background-color: #39B4E7;
@@ -218,11 +220,13 @@ header {
user-select: none; user-select: none;
display: flex; display: flex;
align-items: center; align-items: center;
background-color: white; background-color: #ECECEC;
box-shadow: inset rgba(0, 0, 0, 0.15) 0 0 10px;
width: 60px; width: 60px;
height: 30px; height: 30px;
border-radius: 25px; border-radius: 25px;
padding: 0 3px 0 3px; padding: 0 3px 0 3px;
transition: 200ms background-color;
} }
.toggle-switch .slider { .toggle-switch .slider {
-ms-user-select: none; -ms-user-select: none;
@@ -292,7 +296,7 @@ header {
box-shadow: rgba(0, 0, 0, 0.05) 2px 2px 15px; box-shadow: rgba(0, 0, 0, 0.05) 2px 2px 15px;
border-radius: 25px; border-radius: 25px;
margin: 0 5px 0 5px; margin: 0 5px 0 5px;
padding: 5px 15px 5px 15px; padding: 5px 20px 5px 20px;
transform: translateX(100px); transform: translateX(100px);
} }