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.comments.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";
@@ -21,7 +22,42 @@ switch ($controller->splitted_url[1]) {
$poi->author = $user->id;
$poi->source = "kab";
$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)) {
$poi->permalink = $_POST['permalink'];

View File

@@ -1,65 +1,93 @@
<?
// This array is related to the defined SQL enum, do not touch.
// Types : t_: text ; b_: boolean ; n_: number ; l_: link
<?php
$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",
't_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats",
't_description' => "Description sur l'abri et remarques (mobilier, dates de disponibilité...)",
'b_usable' => "Abri condamné, détruit ou fermé ?",
'b_water' => "Eau à proximité ?",
'b_wood' => "Bois à proximité ?")),
"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(
't_owner' => "Informations sur le⋅la propriétaire et moyens de contacts",
't_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats",
'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 :",
'n_mattress' => "Nombre de matelas disponibles :",
'b_cover' => "Couvertures ?",
'b_water' => "Eau à proximité ?",
'b_wood' => "Bois à proximité ?",
'b_fireplace' => "Cheminée ou poêle à bois ?",
'b_toilet' => "Latrines ou toilettes ?")),
"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(
'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 sur le refuge et remarques (mobilier, isolation, dates de gardiennage, tarifs, prestations, réservations...)",
'b_usable' => "Refuge condamné, détruit ou fermé ?",
'n_bed' => "Nombre de places prévues pour dormir en période gardée :",
'n_bed_winter' => "Nombre de places prévues pour dormir en période non gardée :",
'n_mattress' => "Nombre de matelas en période non gardée :",
'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 ?",
'b_toilet' => "Latrines ou toilettes en période non gardée ?",
'l_water' => "URL du site web :")),
"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_access' => "Description de l'accès, des transports en commun, et d'éventuels passages délicats",
't_description' => "Description sur le gîte et remarques (période d'ouverture, tarifs, prestations, réservations...)",
'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 (réglementation spécifique...)",
'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 (période d'ouverture, tarifs, prestations...)",
'n_bed' => "Nombre d'emplacements :",
'b_water' => "Possibilité de se ravitailler en eau ?",
'l_water' => "URL du site web :"))
"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",
't_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
't_description' => "📝 Description sur l'abri et remarques",
'b_usable' => "🚫 Abri condamné, détruit ou fermé ?",
'b_water' => "💧 Eau à proximité ?",
'b_wood' => "🌲 Bois à proximité ?"
)
),
"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(
't_owner' => "👤 Informations sur le⋅la propriétaire et moyens de contacts",
't_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
't_description' => "📝 Description sur la cabane et remarques",
'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 :",
'n_mattress' => "🛌 Nombre de matelas disponibles :",
'b_cover' => "🧣 Couvertures ?",
'b_water' => "💧 Eau à proximité ?",
'b_wood' => "🌲 Bois à proximité ?",
'b_fireplace' => "🔥 Cheminée ou poêle à bois ?",
'b_toilet' => "🚽 Latrines ou toilettes ?"
)
),
"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(
'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 sur le refuge et remarques",
'b_usable' => "🚫 Refuge condamné, détruit ou fermé ?",
'n_bed' => "Places en période gardée ☀️ :",
'n_bed_winter' => "Places en période non gardée ❄️ :",
'n_mattress' => "🛌 Matelas en période non gardée :",
'b_cover' => "🧣 Couvertures disponibles ?",
'b_water' => "💧 Possibilité de se ravitailler en eau ?",
'b_wood' => "🌲 Bois à proximité ?",
'b_fireplace' => "🔥 Cheminée ou poêle à bois ?",
'b_toilet' => "🚽 Latrines ou toilettes ?",
'l_water' => "URL du site web :"
)
),
"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_access' => "🧭 Description de l'accès, des transports en commun, et d'éventuels passages délicats",
'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)
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");
$this->version_id = pg_fetch_assoc($result)['id'];
@@ -238,7 +238,7 @@ class Poi
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'];

View File

@@ -467,66 +467,112 @@ form.form input[type="checkbox"]:checked + span:before {
}
}
/*****************************************
* CHAMPS GÉNÉRIQUES
*****************************************/
/* Ligne principale : coordonnées + type */
.poi-id-main {
.field {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 19px; /* demandé */
flex-direction: column;
gap: 4px;
padding-bottom: 12px;
}
.field > label {
font-weight: 600;
font-size: 17px;
}
/* Coordonnées */
.poi-id-coords {
display: flex;
align-items: center;
gap: 8px;
/*****************************************
* TEXTES LONGS (t_)
*****************************************/
.field-t .field-value {
padding: 10px 12px;
font-size: 15px;
}
.poi-id-coords a {
color: #0055aa;
text-decoration: none;
}
.poi-id-coords a:hover {
text-decoration: underline;
}
/*****************************************
* NOMBRES ET LIENS EN LIGNE (n_ et l_)
*****************************************/
.poi-id-elev {
color: #333;
}
/* Type */
.poi-id-type {
display: flex;
align-items: center;
/* Label + valeur sur une seule ligne */
.field-n,
.field-l {
flex-direction: row;
align-items: baseline;
gap: 6px;
}
/* Label discret */
.poi-id-label {
font-weight: 500;
color: #444;
/* On enlève le padding bas qui faisait “bloc” */
.field-n,
.field-l {
padding-bottom: 4px;
}
/* Dates en petit */
.poi-id-dates {
font-size: 15px; /* demandé */
color: #555;
display: flex;
gap: 20px;
/* Valeur inline */
.inline-value {
display: inline-block;
font-size: 15px;
color: #222;
}
/* Mobile */
@media (max-width: 700px) {
.poi-id-main {
flex-direction: column;
align-items: flex-start;
gap: 4px;
/* Liens */
.inline-value a {
color: #1a5ad7;
font-weight: 600;
text-decoration: none;
}
.poi-id-dates {
flex-direction: column;
gap: 2px;
.inline-value a:hover {
text-decoration: underline;
}
/*****************************************
* 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>
<? } ?>
<br>
<br>
<h2>Description</h2>
<div class="poi-description">
<?=$poi->content_html?>
<?php
$fields = $poi_types[$poi->poi_type][5];
$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>
<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>
<p id="abstract">
<?=$poi_types[$poi->poi_type][4] ?? ""?>
</p>
<?php endif; ?>
</div>
<h2>Caractéristiques</h2>
<div id="specific_form">
<? if (!empty($poi->parameters)) { ?>
<? foreach ($poi->parameters as $key => $value) { ?>
<div class="flex_line poi_param">
<label><strong><?=$key?></strong></label>
<span><?=$value?></span>
<?php endforeach; ?>
<!-- TABLEAU DES BOOLÉENS -->
<?php if (!empty($bool_fields)): ?>
<div class="bool-grid">
<!-- Ligne des labels -->
<div class="bool-row labels">
<?php foreach ($bool_fields as $key => $label): ?>
<div class="bool-label"><?= $label ?></div>
<?php endforeach; ?>
</div>
<? } ?>
<? } else { ?>
<p>Aucune information spécifique.</p>
<? } ?>
<!-- Ligne des valeurs -->
<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>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
<? if ($poi->is_commentable == 't') { ?>
<h2>Commentaires</h2>