View of a POI is working fine

This commit is contained in:
leosw
2026-01-18 19:40:59 +01:00
parent d2b4f38f0b
commit 0f502d6536
5 changed files with 302 additions and 131 deletions

View File

@@ -3,6 +3,7 @@
require_once($config['models_folder']."d.poi.php"); require_once($config['models_folder']."d.poi.php");
require_once($config['models_folder']."d.comments.php"); require_once($config['models_folder']."d.comments.php");
require_once($config['models_folder']."d.users.php"); require_once($config['models_folder']."d.users.php");
require_once($config['includes_folder']."poi_types.struct.php");
$head['css'] = "d.index.css;d.poi.css"; $head['css'] = "d.index.css;d.poi.css";
@@ -21,7 +22,42 @@ switch ($controller->splitted_url[1]) {
$poi->author = $user->id; $poi->author = $user->id;
$poi->source = "kab"; $poi->source = "kab";
$poi->is_commentable = isset($_POST['is_commentable']) ? 't' : 'f'; $poi->is_commentable = isset($_POST['is_commentable']) ? 't' : 'f';
$poi->parameters = new \stdClass(); // tu pourras y mettre ton JSON plus tard
$definition = $poi_types[$poi->poi_type][5];
$params = [];
foreach ($definition as $key => $label) {
if (isset($_POST[$key])) {
$value = $_POST[$key];
if (str_starts_with($key, 'b_')) {
// 3 états : 1 = oui, 0 = non, -1 = non renseigné
$params[$key] = ($value === "1" ? 1 :
($value === "0" ? 0 : -1));
}
elseif (str_starts_with($key, 'n_')) {
$params[$key] = is_numeric($value) ? (0 + $value) : null;
}
elseif (str_starts_with($key, 't_') || str_starts_with($key, 'l_')) {
$params[$key] = trim($value);
}
else {
$params[$key] = $value;
}
} else {
// Champ absent → booléen = -1 (non renseigné)
if (str_starts_with($key, 'b_')) {
$params[$key] = -1;
} else {
$params[$key] = null;
}
}
}
$poi->parameters = json_encode($params, JSON_UNESCAPED_UNICODE);
if (!$poi->checkPermalink($_POST['permalink'], 1)) { if (!$poi->checkPermalink($_POST['permalink'], 1)) {
$poi->permalink = $_POST['permalink']; $poi->permalink = $_POST['permalink'];

View File

@@ -1,65 +1,93 @@
<? <?php
// This array is related to the defined SQL enum, do not touch.
// Types : t_: text ; b_: boolean ; n_: number ; l_: link
$poi_types = array( $poi_types = array(
"basic_hut" => array("Abri sommaire", "Abri", "#ef2929", "basic_hut", "Un abri sommaire est un bâtiment qui ne permet pas l'hébergement, comme un kiosque.", array(
't_owner' => "Informations sur le⋅la propriétaire et moyens de contacts", "basic_hut" => array("Abri sommaire", "Abri", "#ef2929", "basic_hut",
't_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats", "Un abri sommaire est un bâtiment qui ne permet pas l'hébergement, comme un kiosque.",
't_description' => "Description sur l'abri et remarques (mobilier, dates de disponibilité...)", array(
'b_usable' => "Abri condamné, détruit ou fermé ?", 't_owner' => "👤 Informations sur le⋅la propriétaire et moyens de contacts",
'b_water' => "Eau à proximité ?", 't_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
'b_wood' => "Bois à proximité ?")), 't_description' => "📝 Description sur l'abri et remarques",
"wilderness_hut" => array("Cabane non gardée", "Cabane", "#ef2929", "wilderness_hut", "Une cabane non gardée est un bâtiment qui permet l'hébergement, même sommaire, sans gardien.", array( 'b_usable' => "🚫 Abri condamné, détruit ou fermé ?",
't_owner' => "Informations sur le⋅la propriétaire et moyens de contacts", 'b_water' => "💧 Eau à proximité ?",
't_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats", 'b_wood' => "🌲 Bois à proximité ?"
't_description' => "Description sur la cabane et remarques (mobilier, isolation, dates de disponibilité...)", )
'b_key' => "Nécessite une clé ?", ),
'b_usable' => "Cabane condamnée, détruite ou fermée ?",
'n_bed' => "Nombre de places prévues pour dormir :", "wilderness_hut" => array("Cabane non gardée", "Cabane", "#ef2929", "wilderness_hut",
'n_mattress' => "Nombre de matelas disponibles :", "Une cabane non gardée est un bâtiment qui permet l'hébergement, même sommaire, sans gardien.",
'b_cover' => "Couvertures ?", array(
'b_water' => "Eau à proximité ?", 't_owner' => "👤 Informations sur le⋅la propriétaire et moyens de contacts",
'b_wood' => "Bois à proximité ?", 't_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
'b_fireplace' => "Cheminée ou poêle à bois ?", 't_description' => "📝 Description sur la cabane et remarques",
'b_toilet' => "Latrines ou toilettes ?")), 'b_key' => "🔑 Nécessite une clé ?",
"alpine_hut" => array("Refuge gardé", "Refuge", "#ef2929", "alpine_hut", "Un refuge gardé est un bâtiment qui permet l'hébergement toute l'année, gardé tout ou partie de l'année.", array( 'b_usable' => "🚫 Cabane condamnée, détruite ou fermée ?",
't_owner' => "Informations sur le⋅la propriétaire, le⋅la gardien⋅ne et moyens de contacts", 'n_bed' => "🛏️ Nombre de places prévues pour dormir :",
't_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats", 'n_mattress' => "🛌 Nombre de matelas disponibles :",
't_description' => "Description sur le refuge et remarques (mobilier, isolation, dates de gardiennage, tarifs, prestations, réservations...)", 'b_cover' => "🧣 Couvertures ?",
'b_usable' => "Refuge condamné, détruit ou fermé ?", 'b_water' => "💧 Eau à proximité ?",
'n_bed' => "Nombre de places prévues pour dormir en période gardée :", 'b_wood' => "🌲 Bois à proximité ?",
'n_bed_winter' => "Nombre de places prévues pour dormir en période non gardée :", 'b_fireplace' => "🔥 Cheminée ou poêle à bois ?",
'n_mattress' => "Nombre de matelas en période non gardée :", 'b_toilet' => "🚽 Latrines ou toilettes ?"
'b_cover' => "Couvertures disponibles en période non gardée ?", )
'b_water' => "Possibilité de se ravitailler en eau ?", ),
'b_wood' => "Bois à proximité ?",
'b_fireplace' => "Cheminée ou poêle à bois en période non gardée ?", "alpine_hut" => array("Refuge gardé", "Refuge", "#ef2929", "alpine_hut",
'b_toilet' => "Latrines ou toilettes en période non gardée ?", "Un refuge gardé est un bâtiment qui permet l'hébergement toute l'année, gardé tout ou partie de l'année.",
'l_water' => "URL du site web :")), array(
"halt" => array("Gîte d'étape", "Gîte", "#4e9a06", "halt", "Un gîte d'étape est un bâtiment qui permet l'hébergement uniquement sur ses périodes d'ouvertures.", array( 't_owner' => "👤 Informations sur le⋅la propriétaire, le⋅la gardien⋅ne et moyens de contacts",
't_owner' => "Informations sur le⋅la propriétaire, le⋅la gardien⋅ne et moyens de contacts", 't_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
't_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats", 't_description' => "📝 Description sur le refuge et remarques",
't_description' => "Description sur le gîte et remarques (période d'ouverture, tarifs, prestations, réservations...)", 'b_usable' => "🚫 Refuge condamné, détruit ou fermé ?",
'b_usable' => "Gîte condamné, détruit ou fermé ?", 'n_bed' => "Places en période gardée ☀️ :",
'n_bed' => "Nombre de places prévues pour dormir :", 'n_bed_winter' => "Places en période non gardée ❄️ :",
'b_water' => "Possibilité de se ravitailler en eau ?", 'n_mattress' => "🛌 Matelas en période non gardée :",
'l_water' => "URL du site web :")), 'b_cover' => "🧣 Couvertures disponibles ?",
"bivouac" => array("Zone de bivouac", "Bivouac", "#ef2929", "bivouac", "Une zone de bivouac est un espace aménagé permettant de planter la tente.", array( 'b_water' => "💧 Possibilité de se ravitailler en eau ?",
't_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats", 'b_wood' => "🌲 Bois à proximité ?",
't_description' => "Description sur la zone de bivouac et remarques (réglementation spécifique...)", 'b_fireplace' => "🔥 Cheminée ou poêle à bois ?",
'n_bed' => "Nombre d'emplacements :", 'b_toilet' => "🚽 Latrines ou toilettes ?",
'b_water' => "Eau à proximité ?", 'l_water' => "URL du site web :"
'b_wood' => "Bois à proximité ?", )
'b_fireplace' => "Emplacement pour faire un feu ?")), ),
"campsite" => array("Camping", "Camping", "#4e9a06", "campsite", "Un camping est un espace aménagé permettant de planter la tente plusieurs jours, avec gardien.", array(
't_owner' => "Informations sur le⋅la propriétaire, le⋅la gardien⋅ne et moyens de contacts", "halt" => array("Gîte d'étape", "Gîte", "#4e9a06", "halt",
't_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats", "Un gîte d'étape est un bâtiment qui permet l'hébergement uniquement sur ses périodes d'ouvertures.",
't_description' => "Description du camping et remarques (période d'ouverture, tarifs, prestations...)", array(
'n_bed' => "Nombre d'emplacements :", 't_owner' => "👤 Informations sur le⋅la propriétaire, le⋅la gardien⋅ne et moyens de contacts",
'b_water' => "Possibilité de se ravitailler en eau ?", 't_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
'l_water' => "URL du site web :")) 't_description' => "📝 Description sur le gîte et remarques",
'b_usable' => "🚫 Gîte condamné, détruit ou fermé ?",
'n_bed' => "🛏️ Nombre de places prévues pour dormir :",
'b_water' => "💧 Possibilité de se ravitailler en eau ?",
'l_water' => "URL du site web :"
)
),
"bivouac" => array("Zone de bivouac", "Bivouac", "#ef2929", "bivouac",
"Une zone de bivouac est un espace aménagé permettant de planter la tente.",
array(
't_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
't_description' => "📝 Description sur la zone de bivouac et remarques",
'n_bed' => "⛺ Nombre d'emplacements :",
'b_water' => "💧 Eau à proximité ?",
'b_wood' => "🌲 Bois à proximité ?",
'b_fireplace' => "🔥 Emplacement pour faire un feu ?"
)
),
"campsite" => array("Camping", "Camping", "#4e9a06", "campsite",
"Un camping est un espace aménagé permettant de planter la tente plusieurs jours, avec gardien.",
array(
't_owner' => "👤 Informations sur le⋅la propriétaire, le⋅la gardien⋅ne et moyens de contacts",
't_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
't_description' => "📝 Description du camping et remarques",
'n_bed' => "⛺ Nombre d'emplacements :",
'b_water' => "💧 Possibilité de se ravitailler en eau ?",
'l_water' => "URL du site web :"
)
)
); );
?> ?>

View File

@@ -179,7 +179,7 @@ class Poi
pg_prepare($con, "prepare3", $query) pg_prepare($con, "prepare3", $query)
or die ("Cannot prepare statement\n"); or die ("Cannot prepare statement\n");
$result = pg_execute($con, "prepare3", array(date('r'), $this->name, json_encode($this->parameters), $this->locale_id)) $result = pg_execute($con, "prepare3", array(date('r'), $this->name, $this->parameters, $this->locale_id))
or die ("Cannot execute statement\n"); or die ("Cannot execute statement\n");
$this->version_id = pg_fetch_assoc($result)['id']; $this->version_id = pg_fetch_assoc($result)['id'];
@@ -238,7 +238,7 @@ class Poi
pg_prepare($con, "poi_update_newversion", $query); pg_prepare($con, "poi_update_newversion", $query);
$result = pg_execute($con, "poi_update_newversion", array($this->version, date('r'), $this->name, json_encode($this->parameters), $this->locale_id)); $result = pg_execute($con, "poi_update_newversion", array($this->version, date('r'), $this->name, $this->parameters, $this->locale_id));
$this->version_id = pg_fetch_assoc($result)['id']; $this->version_id = pg_fetch_assoc($result)['id'];

View File

@@ -467,66 +467,112 @@ form.form input[type="checkbox"]:checked + span:before {
} }
} }
/*****************************************
* CHAMPS GÉNÉRIQUES
*****************************************/
/* Ligne principale : coordonnées + type */ .field {
.poi-id-main {
display: flex; display: flex;
justify-content: space-between; flex-direction: column;
align-items: center; gap: 4px;
font-size: 19px; /* demandé */ padding-bottom: 12px;
}
.field > label {
font-weight: 600; font-weight: 600;
font-size: 17px;
} }
/* Coordonnées */ /*****************************************
.poi-id-coords { * TEXTES LONGS (t_)
display: flex; *****************************************/
align-items: center;
gap: 8px; .field-t .field-value {
padding: 10px 12px;
font-size: 15px;
} }
.poi-id-coords a { /*****************************************
color: #0055aa; * NOMBRES ET LIENS EN LIGNE (n_ et l_)
text-decoration: none; *****************************************/
}
.poi-id-coords a:hover {
text-decoration: underline;
}
.poi-id-elev { /* Label + valeur sur une seule ligne */
color: #333; .field-n,
} .field-l {
flex-direction: row;
/* Type */ align-items: baseline;
.poi-id-type {
display: flex;
align-items: center;
gap: 6px; gap: 6px;
} }
/* Label discret */ /* On enlève le padding bas qui faisait “bloc” */
.poi-id-label { .field-n,
font-weight: 500; .field-l {
color: #444; padding-bottom: 4px;
} }
/* Dates en petit */ /* Valeur inline */
.poi-id-dates { .inline-value {
font-size: 15px; /* demandé */ display: inline-block;
color: #555; font-size: 15px;
display: flex; color: #222;
gap: 20px;
} }
/* Mobile */ /* Liens */
@media (max-width: 700px) { .inline-value a {
.poi-id-main { color: #1a5ad7;
flex-direction: column; font-weight: 600;
align-items: flex-start; text-decoration: none;
gap: 4px;
} }
.poi-id-dates { .inline-value a:hover {
flex-direction: column; text-decoration: underline;
gap: 2px; }
/*****************************************
* Booleans grid in poi view
*****************************************/
.bool-grid {
margin: 20px 0 0 0;
padding: 20px 15px;
background: rgba(200, 220, 255, 0.25);
border-top: 1px solid #bbb;
}
.bool-row {
display: grid;
grid-auto-flow: column;
grid-auto-columns: 1fr;
text-align: center;
margin-bottom: 10px;
}
.bool-row.labels {
font-weight: 600;
font-size: 16px;
}
.bool-label {
padding: 5px;
}
.bool-row.values {
margin-top: 5px;
}
.boolean-pill {
display: inline-block;
padding: 8px 12px;
border-radius: 20px;
font-weight: 700;
font-size: 18px;
background: white;
}
@media (max-width: 900px) {
.bool-row {
grid-auto-flow: row;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
} }
} }

View File

@@ -75,33 +75,94 @@
</span> </span>
<? } ?> <? } ?>
<br>
<br> <br>
<h2>Description</h2> <?php
<div class="poi-description"> $fields = $poi_types[$poi->poi_type][5];
<?=$poi->content_html?> $values = $poi->parameters ?? [];
// Séparer les booléens des autres champs
$bool_fields = [];
$other_fields = [];
foreach ($fields as $key => $label) {
if ($key[0] === 'b') {
$bool_fields[$key] = $label;
} else {
$other_fields[$key] = $label;
}
}
?>
<div id="specific_form" class="view-mode">
<!-- AUTRES CHAMPS (texte, nombre, lien) -->
<?php foreach ($other_fields as $key => $label): ?>
<?php
$value = $values[$key] ?? null;
$type = $key[0];
?>
<div class="field field-<?= $type ?>">
<label><?= $label ?></label>
<?php if ($type === 'n'): ?>
<span class="inline-value"><?= $value !== null ? $value : "<em>—</em>" ?></span>
<?php elseif ($type === 't'): ?>
<div class="field-value">
<?= $value ? nl2br(htmlspecialchars($value)) : "<em>Aucune information.</em>" ?>
</div> </div>
<hr> <?php elseif ($type === 'l'): ?>
<span class="inline-value">
<?php if ($value): ?>
<a href="<?= htmlspecialchars($value) ?>" target="_blank"><?= $value ?></a>
<?php else: ?>
<em></em>
<?php endif; ?>
</span>
<h2 id="abstract_title">Informations générales</h2> <?php endif; ?>
<p id="abstract"> </div>
<?=$poi_types[$poi->poi_type][4] ?? ""?>
</p>
<h2>Caractéristiques</h2>
<div id="specific_form"> <?php endforeach; ?>
<? if (!empty($poi->parameters)) { ?>
<? foreach ($poi->parameters as $key => $value) { ?> <!-- TABLEAU DES BOOLÉENS -->
<div class="flex_line poi_param"> <?php if (!empty($bool_fields)): ?>
<label><strong><?=$key?></strong></label> <div class="bool-grid">
<span><?=$value?></span>
<!-- Ligne des labels -->
<div class="bool-row labels">
<?php foreach ($bool_fields as $key => $label): ?>
<div class="bool-label"><?= $label ?></div>
<?php endforeach; ?>
</div> </div>
<? } ?>
<? } else { ?> <!-- Ligne des valeurs -->
<p>Aucune information spécifique.</p> <div class="bool-row values">
<? } ?> <?php foreach ($bool_fields as $key => $label): ?>
<?php
$value = $values[$key] ?? -1;
$icon = [
1 => "<span class='boolean-pill boolean-yes'>✔️</span>",
0 => "<span class='boolean-pill boolean-no'>❌</span>",
-1 => "<span class='boolean-pill boolean-unknown'>❓</span>"
][$value];
?>
<div class="bool-cell">
<?= $icon ?>
</div> </div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
<? if ($poi->is_commentable == 't') { ?> <? if ($poi->is_commentable == 't') { ?>
<h2>Commentaires</h2> <h2>Commentaires</h2>